5

I've started with this base project (React Native Firebase):

https://github.com/invertase/react-native-firebase

I've integrated React Native Navigation V2:

https://wix.github.io/react-native-navigation/v2/#/

as well as React Native Splash Screen (npm package react-native-splash-screen):

https://github.com/crazycodeboy/react-native-splash-screen

which was integrated based on this tutorial:

https://medium.com/handlebar-labs/how-to-add-a-splash-screen-to-a-react-native-app-ios-and-android-30a3cec835ae

Per the react-native-navigation docs, my most recent changes have been to setRoot() to the SplashScreen inside my Navigation.onAppLaunched(()=>{Navigation.setRoot({...})}) and then once the SplashScreen component is mounted, it uses setRoot() to navigate to the LoginScreen.

It looks nice, but when the app finishes loading and lands on the Login Screen, no touches will work on the screen unless I open and close the inspector using Cmd+m > "toggle inspector".

Here's some code, first AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jaqstudios.plantlife"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="22" />

    <application
      android:name=".MainApplication"
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:theme="@style/AppTheme">
      <activity
        android:name=".SplashActivity"
        android:theme="@style/SplashTheme"
        android:label="@string/app_name">
        <intent-filter>
          <action android:name="android.intent.action.MAIN" />
          <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize"
        android:exported="true"
      />
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

Here's the MainActivity, which extends NavigationActivity from the react-native-navigation package:

package com.jaqstudios.plantlife;
import com.reactnativenavigation.NavigationActivity;
import org.devio.rn.splashscreen.SplashScreen; // import this
import android.os.Bundle; // import this
public class MainActivity extends NavigationActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SplashScreen.show(this);
        super.onCreate(savedInstanceState);
    }
}

Here's the SplashActivity which is supposed to happen i guess before the NavigationActivity:

package com.jaqstudios.plantlife;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();
    }
}

And then in the js world my index.js is:

import { AppRegistry } from 'react-native';
import { PlantLifeApp, start } from './src/PlantLifeApp';
// AppRegistry.registerComponent('plantlife', () => PlantLifeApp);
start();

Here's where the start function is defined, in my main App.js file:

import React from 'react';
import { StyleSheet, Platform, Image, Text, View, ScrollView } from 'react-native';

import firebase, { RNFirebase } from 'react-native-firebase';

import { Navigation } from 'react-native-navigation';
import registerScreens from './screens';
import testIDs from './testIDs';

import * as RNFB from '../assets/RNFirebase.png';

if (Platform.OS === 'android') {
  alert = (title) => {
    consloe.log('ALERT CALLED');
    // Navigation.showOverlay({
    //   component: {
    //     name: 'navigation.playground.alert',
    //     passProps: {
    //       title
    //     },
    //     options: {
    //       overlay: {
    //         interceptTouchOutside: true
    //       }
    //     }
    //   }
    // });
  };
}
console.log('PlantLifeApp starting...');

export function start() {
  registerScreens();
  Navigation.events().onAppLaunched(() => {
    Navigation.setDefaultOptions({
      _animations: {
        startApp: {
          y: {
            from: 1000,
            to: 0,
            duration: 500,
            interpolation: 'accelerate',
          },
          alpha: {
            from: 0,
            to: 1,
            duration: 500,
            interpolation: 'accelerate'
          }
        },
        push: {
          topBar: {
            id: 'TEST',
            alpha: {
              from: 0,
              to: 1,
              duration: 500,
              interpolation: 'accelerate'
            }
          },
          bottomTabs: {
            y: {
              from: 1000,
              to: 0,
              duration: 500,
              interpolation: 'decelerate',
            },
            alpha: {
              from: 0,
              to: 1,
              duration: 500,
              interpolation: 'decelerate'
            }
          },
          bottomTabs: {
            y: {
              from: 1000,
              to: 0,
              duration: 500,
              interpolation: 'decelerate',
            },
            alpha: {
              from: 0,
              to: 1,
              duration: 500,
              interpolation: 'decelerate'
            }
          },
          content: {
            y: {
              from: 1000,
              to: 0,
              duration: 500,
              interpolation: 'accelerate',
            },
            alpha: {
              from: 0,
              to: 1,
              duration: 500,
              interpolation: 'accelerate'
            }
          }
        },
        pop: {
          topBar: {
            id: 'TEST',
            alpha: {
              from: 1,
              to: 0,
              duration: 500,
              interpolation: 'accelerate'
            }
          },
          bottomTabs: {
            y: {
              from: 0,
              to: 100,
              duration: 500,
              interpolation: 'accelerate',
            },
            alpha: {
              from: 1,
              to: 0,
              duration: 500,
              interpolation: 'accelerate'
            }
          },
          bottomTabs: {
            y: {
              from: 0,
              to: 100,
              duration: 500,
              interpolation: 'decelerate',
            },
            alpha: {
              from: 1,
              to: 0,
              duration: 500,
              interpolation: 'decelerate'
            }
          },
          content: {
            y: {
              from: 0,
              to: 1000,
              duration: 500,
              interpolation: 'decelerate',
            },
            alpha: {
              from: 1,
              to: 0,
              duration: 500,
              interpolation: 'decelerate'
            }
          }
        }
      }
    });
    Navigation.setRoot({
      component: {
        name: 'navigation.playground.SplashScreen'
      }
    });
    console.log('app launched, navigation root set...');
  });
}

export class PlantLifeApp extends React.Component {
  constructor() {
    super();
    this.state = {
      // firebase things?
    };
  }

  componentDidMount() {
    // firebase things?
  }

  render() {
    return (
      <ScrollView>
        <View style={styles.container}>
        <Image source={ RNFB } style={[styles.logo]} />
        <Text style={styles.instructions}>
          Current selected menu item is: {this.state.selectedItem}
        </Text>
        <Text style={styles.welcome}>
          Welcome to the React Native{'\n'}Firebase starter project!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit App.js
        </Text>
        {Platform.OS === 'ios' ? (
          <Text style={styles.instructions}>
            Press Cmd+R to reload,{'\n'}
            Cmd+D or shake for dev menu
          </Text>
        ) : (
          <Text style={styles.instructions}>
            Double tap R on your keyboard to reload,{'\n'}
            Cmd+M or shake for dev menu
          </Text>
        )}
        <View style={styles.modules}>
          <Text style={styles.modulesHeader}>The following Firebase modules are enabled:</Text>
          {firebase.admob.nativeModuleExists && <Text style={styles.module}>Admob</Text>}
        </View>
        </View>    
      </ScrollView>
    );
  }
}

Here's where I register the screens:

import { Navigation } from 'react-native-navigation';
import SplashScreen from './SplashScreen';
import LoginScreen from './LoginScreen';
import WelcomeScreen from './WelcomeScreen';
import SideMenuScreen from './SideMenuScreen';
import PlantListScreen from './PlantListScreen';

export default function registerScreens() {
    Navigation.registerComponent(`navigation.playground.SplashScreen`, () => SplashScreen)
    Navigation.registerComponent(`navigation.playground.LoginScreen`, () => LoginScreen)
    Navigation.registerComponent(`navigation.playground.WelcomeScreen`, () => WelcomeScreen);
    Navigation.registerComponent('navigation.playground.SideMenuScreen', () => SideMenuScreen);
    Navigation.registerComponent(`navigation.playground.PlantListScreen`, () => PlantListScreen);
    console.log('screens registered...');
}

Here's the SplashScreen:

import React, { Component } from 'react';
import {
  Platform,
  StyleSheet,
  Text,
  View,
  StatusBar
} from 'react-native';

import RNSS from 'react-native-splash-screen';
import { Navigation } from 'react-native-navigation';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' +
    'Cmd+D or shake for dev menu',
  android: 'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
});

export default class SplashScreen extends Component {
    componentDidMount() {
        RNSS.hide();
        Navigation.setRoot({
            component: {
                name: 'navigation.playground.LoginScreen'
            }
        });
    }
  render() {
    return (
      <View style={styles.container}>
        <StatusBar
          barStyle="light-content"
          backgroundColor="#4F6D7A"
        />
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit App.js
        </Text>
        <Text style={styles.instructions}>
          {instructions}
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#4F6D7A',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    color: '#F5FCFF',
  },
  instructions: {
    textAlign: 'center',
    color: '#F5FCFF',
    marginBottom: 5,
  },
});

And finally, here's the LoginScreen:

import React, { Component } from 'react';
import {
  View,
  Image,
  StyleSheet,
  TextInput,
  TouchableOpacity,
  Text
} from 'react-native';
import gembul from '../../assets/gembul.png';

export default class LoginScreen extends Component {
  state = {
    logging: false
  };
  // This is for demo only, normally you want to create an api wrapper
  async callLoginAPI() {
    this.setState({ logging: true });
    await new Promise(resolve => {
      setTimeout(resolve, 2000);
    });
    alert('SIGN IN success');
    this.setState({ logging: false });
  }
  render() {
    return (
      <View style={styles.container}>
        <View
          style={{
            flex: 1
          }}
        >
          <Image
            resizeMode="cover"
            style={[
              {
                width: '100%',
                height: '100%',
                overflow: 'visible'
              }
            ]}
            source={gembul}
          />
        </View>
        <TextInput
          placeholder="Username"
          style={[styles.textInput, { marginTop: 40 }]}
        />
        <TextInput
          placeholder="Password"
          style={[styles.textInput, { marginVertical: 20 }]}
        />

        <TouchableOpacity
          onPress={() => {
            this.callLoginAPI();
          }}
          style={[styles.button]}
        >
          <Text style={{ color: 'white', fontSize: 20, fontWeight: '600' }}>
            SIGN IN
          </Text>
        </TouchableOpacity>
        <TouchableOpacity
          style={{
            alignSelf: 'flex-end',
            height: 40,
            justifyContent: 'center',
            marginBottom: 20
          }}
        >
          <Text style={{ color: '#BDC3C6', fontSize: 15 }}>
            Need Help?
          </Text>
        </TouchableOpacity>
        <Text style={{ alignSelf: 'center', color: '#A6A8A9', fontSize: 15 }}>
          Don’t have an account yet ?
        </Text>
        <TouchableOpacity
          style={{
            alignSelf: 'center',
            height: 34,
            justifyContent: 'center'
          }}
        >
          <Text style={{ color: '#0D92CA', fontSize: 15 }}>
            Create an account
          </Text>
        </TouchableOpacity>
      </View>
    );
  }
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingHorizontal: 26,
    paddingTop: 26,
    paddingBottom: 18
  },
  logo: {
    flex: 1,
    alignItems: 'center',
    backgroundColor: 'grey'
  },
  textInput: {
    height: 60,
    borderRadius: 3,
    borderWidth: 1,
    borderColor: '#ECF0F3',
    paddingHorizontal: 19
  },
  button: {
    height: 60,
    borderRadius: 3,
    backgroundColor: '#11B8FF',
    justifyContent: 'center',
    alignItems: 'center'
  }
});

Mentioned above, the flow all seems fine. The app opens to the splash screen, the splash screen is closed by RNSS.hide(), and Navigation.setRoot() sends the users to the LoginScreen in the SplashScreen componentDidMount. But once the LoginScreen appears, no screen touches on my application are registered (i.e. I cannot modify the login credentials) unless I toggle the inspector. I should also note that my login screen is derived from the following tutorial:

https://medium.com/@bosung90/use-higher-order-component-in-react-native-df44e634e860

I was unable to get the first step working from the first snippet, which is a simple login page that is basically copy pasted from that tutorials first code snippet:

https://gist.github.com/bosung90/66f70041586a8e05b41a60ee09109519

Thanks.

omgoshjosh
  • 83
  • 1
  • 9
  • Hi, I have the same problem. Im using a different dependencies but we have Wix/RNN v2 in common. Another dependencies are redux, redux-persist. I suspect it was something in between, after I add this deps the app start showing this problems. Did you find the problem? I'm still hunting the issue. – AXSM Oct 22 '18 at 22:51
  • probably not actually, but i met the same issue but rebuilding my app and restarting the emulator helped me – Roma Rush Jan 20 '22 at 22:59

0 Answers0