5

我从这个基础项目(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

这是基于本教程集成的:

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

根据 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

谢谢。

4

0 回答 0