React Native - 使用启动屏幕和 navigation.setRoot() 初始化应用程序后触摸不起作用

omg*_*osh 5 android splash-screen react-native react-native-navigation react-native-firebase

我已经开始这个基础项目(React Native Firebase):

\n\n

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

\n\n

我已经集成了 React Native Navigation V2:

\n\n

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

\n\n

以及 React Native 启动屏幕(npm 包react-native-splash-screen):

\n\n

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

\n\n

根据本教程集成:

\n\n

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

\n\n

根据react-native-navigation文档,我最近的更改是setRoot()对我内部的SplashScreen进行的Navigation.onAppLaunched(()=>{Navigation.setRoot({...})}),然后一旦安装了SplashScreen组件,它就会用于setRoot()导航到LoginScreen。

\n\n

它看起来不错,但是当应用程序完成加载并登陆登录屏幕时,除非我使用 Cmd+m >“切换检查器”打开和关闭检查器,否则屏幕上不会出现任何触摸操作。

\n\n

这是一些代码,首先是 AndroidManifest.xml:

\n\n
<manifest xmlns:android="http://schemas.android.com/apk/res/android"\n    package="com.jaqstudios.plantlife"\n    android:versionCode="1"\n    android:versionName="1.0">\n\n    <uses-permission android:name="android.permission.INTERNET" />\n    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>\n\n    <uses-sdk\n        android:minSdkVersion="16"\n        android:targetSdkVersion="22" />\n\n    <application\n      android:name=".MainApplication"\n      android:allowBackup="true"\n      android:label="@string/app_name"\n      android:icon="@mipmap/ic_launcher"\n      android:theme="@style/AppTheme">\n      <activity\n        android:name=".SplashActivity"\n        android:theme="@style/SplashTheme"\n        android:label="@string/app_name">\n        <intent-filter>\n          <action android:name="android.intent.action.MAIN" />\n          <category android:name="android.intent.category.LAUNCHER" />\n        </intent-filter>\n      </activity>\n      <activity\n        android:name=".MainActivity"\n        android:label="@string/app_name"\n        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"\n        android:windowSoftInputMode="adjustResize"\n        android:exported="true"\n      />\n      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />\n    </application>\n\n</manifest>\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是MainActivity,它从react-native-navigation包扩展了NavigationActivity:

\n\n
package com.jaqstudios.plantlife;\nimport com.reactnativenavigation.NavigationActivity;\nimport org.devio.rn.splashscreen.SplashScreen; // import this\nimport android.os.Bundle; // import this\npublic class MainActivity extends NavigationActivity {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        SplashScreen.show(this);\n        super.onCreate(savedInstanceState);\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是 SplashActivity,我猜它应该在 NavigationActivity 之前发生:

\n\n
package com.jaqstudios.plantlife;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\n\npublic class SplashActivity extends AppCompatActivity {\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        Intent intent = new Intent(this, MainActivity.class);\n        startActivity(intent);\n        finish();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后在 js 世界中我的 index.js 是:

\n\n
import { AppRegistry } from \'react-native\';\nimport { PlantLifeApp, start } from \'./src/PlantLifeApp\';\n// AppRegistry.registerComponent(\'plantlife\', () => PlantLifeApp);\nstart();\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是在我的主 App.js 文件中定义启动函数的位置:

\n\n
import React from \'react\';\nimport { StyleSheet, Platform, Image, Text, View, ScrollView } from \'react-native\';\n\nimport firebase, { RNFirebase } from \'react-native-firebase\';\n\nimport { Navigation } from \'react-native-navigation\';\nimport registerScreens from \'./screens\';\nimport testIDs from \'./testIDs\';\n\nimport * as RNFB from \'../assets/RNFirebase.png\';\n\nif (Platform.OS === \'android\') {\n  alert = (title) => {\n    consloe.log(\'ALERT CALLED\');\n    // Navigation.showOverlay({\n    //   component: {\n    //     name: \'navigation.playground.alert\',\n    //     passProps: {\n    //       title\n    //     },\n    //     options: {\n    //       overlay: {\n    //         interceptTouchOutside: true\n    //       }\n    //     }\n    //   }\n    // });\n  };\n}\nconsole.log(\'PlantLifeApp starting...\');\n\nexport function start() {\n  registerScreens();\n  Navigation.events().onAppLaunched(() => {\n    Navigation.setDefaultOptions({\n      _animations: {\n        startApp: {\n          y: {\n            from: 1000,\n            to: 0,\n            duration: 500,\n            interpolation: \'accelerate\',\n          },\n          alpha: {\n            from: 0,\n            to: 1,\n            duration: 500,\n            interpolation: \'accelerate\'\n          }\n        },\n        push: {\n          topBar: {\n            id: \'TEST\',\n            alpha: {\n              from: 0,\n              to: 1,\n              duration: 500,\n              interpolation: \'accelerate\'\n            }\n          },\n          bottomTabs: {\n            y: {\n              from: 1000,\n              to: 0,\n              duration: 500,\n              interpolation: \'decelerate\',\n            },\n            alpha: {\n              from: 0,\n              to: 1,\n              duration: 500,\n              interpolation: \'decelerate\'\n            }\n          },\n          bottomTabs: {\n            y: {\n              from: 1000,\n              to: 0,\n              duration: 500,\n              interpolation: \'decelerate\',\n            },\n            alpha: {\n              from: 0,\n              to: 1,\n              duration: 500,\n              interpolation: \'decelerate\'\n            }\n          },\n          content: {\n            y: {\n              from: 1000,\n              to: 0,\n              duration: 500,\n              interpolation: \'accelerate\',\n            },\n            alpha: {\n              from: 0,\n              to: 1,\n              duration: 500,\n              interpolation: \'accelerate\'\n            }\n          }\n        },\n        pop: {\n          topBar: {\n            id: \'TEST\',\n            alpha: {\n              from: 1,\n              to: 0,\n              duration: 500,\n              interpolation: \'accelerate\'\n            }\n          },\n          bottomTabs: {\n            y: {\n              from: 0,\n              to: 100,\n              duration: 500,\n              interpolation: \'accelerate\',\n            },\n            alpha: {\n              from: 1,\n              to: 0,\n              duration: 500,\n              interpolation: \'accelerate\'\n            }\n          },\n          bottomTabs: {\n            y: {\n              from: 0,\n              to: 100,\n              duration: 500,\n              interpolation: \'decelerate\',\n            },\n            alpha: {\n              from: 1,\n              to: 0,\n              duration: 500,\n              interpolation: \'decelerate\'\n            }\n          },\n          content: {\n            y: {\n              from: 0,\n              to: 1000,\n              duration: 500,\n              interpolation: \'decelerate\',\n            },\n            alpha: {\n              from: 1,\n              to: 0,\n              duration: 500,\n              interpolation: \'decelerate\'\n            }\n          }\n        }\n      }\n    });\n    Navigation.setRoot({\n      component: {\n        name: \'navigation.playground.SplashScreen\'\n      }\n    });\n    console.log(\'app launched, navigation root set...\');\n  });\n}\n\nexport class PlantLifeApp extends React.Component {\n  constructor() {\n    super();\n    this.state = {\n      // firebase things?\n    };\n  }\n\n  componentDidMount() {\n    // firebase things?\n  }\n\n  render() {\n    return (\n      <ScrollView>\n        <View style={styles.container}>\n        <Image source={ RNFB } style={[styles.logo]} />\n        <Text style={styles.instructions}>\n          Current selected menu item is: {this.state.selectedItem}\n        </Text>\n        <Text style={styles.welcome}>\n          Welcome to the React Native{\'\\n\'}Firebase starter project!\n        </Text>\n        <Text style={styles.instructions}>\n          To get started, edit App.js\n        </Text>\n        {Platform.OS === \'ios\' ? (\n          <Text style={styles.instructions}>\n            Press Cmd+R to reload,{\'\\n\'}\n            Cmd+D or shake for dev menu\n          </Text>\n        ) : (\n          <Text style={styles.instructions}>\n            Double tap R on your keyboard to reload,{\'\\n\'}\n            Cmd+M or shake for dev menu\n          </Text>\n        )}\n        <View style={styles.modules}>\n          <Text style={styles.modulesHeader}>The following Firebase modules are enabled:</Text>\n          {firebase.admob.nativeModuleExists && <Text style={styles.module}>Admob</Text>}\n        </View>\n        </View>    \n      </ScrollView>\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我注册屏幕的地方:

\n\n
import { Navigation } from \'react-native-navigation\';\nimport SplashScreen from \'./SplashScreen\';\nimport LoginScreen from \'./LoginScreen\';\nimport WelcomeScreen from \'./WelcomeScreen\';\nimport SideMenuScreen from \'./SideMenuScreen\';\nimport PlantListScreen from \'./PlantListScreen\';\n\nexport default function registerScreens() {\n    Navigation.registerComponent(`navigation.playground.SplashScreen`, () => SplashScreen)\n    Navigation.registerComponent(`navigation.playground.LoginScreen`, () => LoginScreen)\n    Navigation.registerComponent(`navigation.playground.WelcomeScreen`, () => WelcomeScreen);\n    Navigation.registerComponent(\'navigation.playground.SideMenuScreen\', () => SideMenuScreen);\n    Navigation.registerComponent(`navigation.playground.PlantListScreen`, () => PlantListScreen);\n    console.log(\'screens registered...\');\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是启动画面:

\n\n
import React, { Component } from \'react\';\nimport {\n  Platform,\n  StyleSheet,\n  Text,\n  View,\n  StatusBar\n} from \'react-native\';\n\nimport RNSS from \'react-native-splash-screen\';\nimport { Navigation } from \'react-native-navigation\';\n\nconst instructions = Platform.select({\n  ios: \'Press Cmd+R to reload,\\n\' +\n    \'Cmd+D or shake for dev menu\',\n  android: \'Double tap R on your keyboard to reload,\\n\' +\n    \'Shake or press menu button for dev menu\',\n});\n\nexport default class SplashScreen extends Component {\n    componentDidMount() {\n        RNSS.hide();\n        Navigation.setRoot({\n            component: {\n                name: \'navigation.playground.LoginScreen\'\n            }\n        });\n    }\n  render() {\n    return (\n      <View style={styles.container}>\n        <StatusBar\n          barStyle="light-content"\n          backgroundColor="#4F6D7A"\n        />\n        <Text style={styles.welcome}>\n          Welcome to React Native!\n        </Text>\n        <Text style={styles.instructions}>\n          To get started, edit App.js\n        </Text>\n        <Text style={styles.instructions}>\n          {instructions}\n        </Text>\n      </View>\n    );\n  }\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: \'center\',\n    alignItems: \'center\',\n    backgroundColor: \'#4F6D7A\',\n  },\n  welcome: {\n    fontSize: 20,\n    textAlign: \'center\',\n    margin: 10,\n    color: \'#F5FCFF\',\n  },\n  instructions: {\n    textAlign: \'center\',\n    color: \'#F5FCFF\',\n    marginBottom: 5,\n  },\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,这是登录屏幕:

\n\n
import React, { Component } from \'react\';\nimport {\n  View,\n  Image,\n  StyleSheet,\n  TextInput,\n  TouchableOpacity,\n  Text\n} from \'react-native\';\nimport gembul from \'../../assets/gembul.png\';\n\nexport default class LoginScreen extends Component {\n  state = {\n    logging: false\n  };\n  // This is for demo only, normally you want to create an api wrapper\n  async callLoginAPI() {\n    this.setState({ logging: true });\n    await new Promise(resolve => {\n      setTimeout(resolve, 2000);\n    });\n    alert(\'SIGN IN success\');\n    this.setState({ logging: false });\n  }\n  render() {\n    return (\n      <View style={styles.container}>\n        <View\n          style={{\n            flex: 1\n          }}\n        >\n          <Image\n            resizeMode="cover"\n            style={[\n              {\n                width: \'100%\',\n                height: \'100%\',\n                overflow: \'visible\'\n              }\n            ]}\n            source={gembul}\n          />\n        </View>\n        <TextInput\n          placeholder="Username"\n          style={[styles.textInput, { marginTop: 40 }]}\n        />\n        <TextInput\n          placeholder="Password"\n          style={[styles.textInput, { marginVertical: 20 }]}\n        />\n\n        <TouchableOpacity\n          onPress={() => {\n            this.callLoginAPI();\n          }}\n          style={[styles.button]}\n        >\n          <Text style={{ color: \'white\', fontSize: 20, fontWeight: \'600\' }}>\n            SIGN IN\n          </Text>\n        </TouchableOpacity>\n        <TouchableOpacity\n          style={{\n            alignSelf: \'flex-end\',\n            height: 40,\n            justifyContent: \'center\',\n            marginBottom: 20\n          }}\n        >\n          <Text style={{ color: \'#BDC3C6\', fontSize: 15 }}>\n            Need Help?\n          </Text>\n        </TouchableOpacity>\n        <Text style={{ alignSelf: \'center\', color: \'#A6A8A9\', fontSize: 15 }}>\n          Don\xe2\x80\x99t have an account yet ?\n        </Text>\n        <TouchableOpacity\n          style={{\n            alignSelf: \'center\',\n            height: 34,\n            justifyContent: \'center\'\n          }}\n        >\n          <Text style={{ color: \'#0D92CA\', fontSize: 15 }}>\n            Create an account\n          </Text>\n        </TouchableOpacity>\n      </View>\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    paddingHorizontal: 26,\n    paddingTop: 26,\n    paddingBottom: 18\n  },\n  logo: {\n    flex: 1,\n    alignItems: \'center\',\n    backgroundColor: \'grey\'\n  },\n  textInput: {\n    height: 60,\n    borderRadius: 3,\n    borderWidth: 1,\n    borderColor: \'#ECF0F3\',\n    paddingHorizontal: 19\n  },\n  button: {\n    height: 60,\n    borderRadius: 3,\n    backgroundColor: \'#11B8FF\',\n    justifyContent: \'center\',\n    alignItems: \'center\'\n  }\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

上面提到,流程似乎一切都很好。应用程序打开到启动屏幕,启动屏幕通过 关闭RNSS.hide(),并将Navigation.setRoot()用户发送到 SplashScreen componentDidMount 中的 LoginScreen。但是,一旦出现登录屏幕,除非我切换检查器,否则我的应用程序上不会注册任何屏幕触摸(即我无法修改登录凭据)。我还应该注意,我的登录屏幕来自以下教程:

\n\n

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

\n\n

我无法从第一个代码片段开始执行第一步,这是一个简单的登录页面,基本上是从教程的第一个代码片段复制粘贴的:

\n\n

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

\n\n

谢谢。

\n