我从这个基础项目(React Native Firebase)开始:
https://github.com/invertase/react-native-firebase
我已经集成了 React Native Navigation V2:
https://wix.github.io/react-native-navigation/v2/#/
以及 React Native Splash Screen(npm 包 react-native-splash-screen):
https://github.com/crazycodeboy/react-native-splash-screen
这是基于本教程集成的:
根据 react-native-navigation 文档,我最近的更改是对setRoot()
我内部的 SplashScreen 进行了更改Navigation.onAppLaunched(()=>{Navigation.setRoot({...})})
,然后一旦安装了 SplashScreen 组件,它就会用于setRoot()
导航到 LoginScreen。
它看起来不错,但是当应用程序完成加载并登陆登录屏幕时,除非我使用 Cmd+m >“切换检查器”打开和关闭检查器,否则屏幕上不会有任何触摸。
这是一些代码,首先是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>
这是 MainActivity,它从 react-native-navigation 包中扩展 NavigationActivity:
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);
}
}
这是我猜在 NavigationActivity 之前应该发生的 SplashActivity:
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();
}
}
然后在 js 世界中,我的 index.js 是:
import { AppRegistry } from 'react-native';
import { PlantLifeApp, start } from './src/PlantLifeApp';
// AppRegistry.registerComponent('plantlife', () => PlantLifeApp);
start();
这是在我的主 App.js 文件中定义 start 函数的位置:
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>
);
}
}
这是我注册屏幕的地方:
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...');
}
这是启动画面:
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,
},
});
最后,这是登录屏幕:
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'
}
});
上面提到,流程似乎都很好。应用打开闪屏,闪屏由 关闭RNSS.hide()
,Navigation.setRoot()
并将用户发送到SplashScreen 组件DidMount 中的LoginScreen。但是一旦出现 LoginScreen,除非我切换检查器,否则我的应用程序上的任何屏幕触摸都不会被注册(即我无法修改登录凭据)。我还应该注意,我的登录屏幕来自以下教程:
https://medium.com/@bosung90/use-higher-order-component-in-react-native-df44e634e860
我无法从第一个片段开始第一步,这是一个简单的登录页面,基本上是从该教程的第一个代码片段中复制粘贴的:
https://gist.github.com/bosung90/66f70041586a8e05b41a60ee09109519
谢谢。