简体   繁体   English

React Native & Expo,如何控制闪屏?

[英]React Native & Expo, how to control the splash screen?

I'm using the built in splash screen in expo that you add in app.json for a simple test app.我正在使用您在app.json中添加的 expo 中内置的启动屏幕,用于一个简单的测试应用程序。 However I noticed that my start screen flashes in default mode 1 millisecond before showing the assets that I've added with AsyncStorage .但是,我注意到在显示我使用AsyncStorage添加的资产之前,我的开始屏幕会以默认模式闪烁 1 毫秒。

I've tried using splash-screen package from expo but I found it a bit confusing.我尝试过使用 expo 中的闪屏包,但我发现它有点令人困惑。 Is there a fairly easy way to add in my App.js this logic :有没有一种相当简单的方法可以在我的App.js中添加这个逻辑:

Show a splash screen and when all assets are loaded, load this setup (with my contexts and screens), or just increase loading time of the build in splash screen from expo (because I assume it loads over the assets being fetched?).显示一个启动画面,当所有资产都加载完毕时,加载这个设置(使用我的上下文和屏幕),或者只是增加来自 expo 的启动画面中构建的加载时间(因为我假设它加载了正在获取的资产?)。

const App = () => {

  const [selectedTheme, setSelectedTheme] = useState(themes.light)

  const changeTheme = async () =>{
    try {
      const theme = await AsyncStorage.getItem("MyTheme")
      if (theme === "dark"){
      setSelectedTheme(themes.nightSky)} 
      else if (theme === "light") {
        setSelectedTheme(themes.arctic)
        }
    } catch (err) {alert(err)}
  }
  
  useEffect(()=> {
    changeTheme()
  },[])


  return (
    <ThemeContext.Provider value={{selectedTheme, changeTheme}}>
         <NavigationContainer>
            <Stack.Navigator screenOptions={{headerShown:false, presentation: 'modal'}}>
              <Stack.Screen name="Home" component={home}/>
            </Stack.Navigator>
          </NavigationContainer>
    </ThemeContext.Provider>

  );
};

First solution:第一个解决方案:

You could use SplashScreen module from Expo.您可以使用 Expo 的SplashScreen模块。 Here is an overview of how you could use it:以下是如何使用它的概述:

expo install expo-splash-screen
import * as SplashScreen from "expo-splash-screen";
import React, { useCallback, useEffect, useState } from "react";
import { Text, View } from "react-native";

export default function App() {
  const [appIsReady, setAppIsReady] = useState(false);

  useEffect(() => {
    async function prepare() {
      // Keep the splash screen visible
      await SplashScreen.preventAutoHideAsync();
      // Do what you need before the splash screen gets hidden
      console.log("I'm a task that gets executed before splash screen disappears");
      // Then tell the application to render
      setAppIsReady(true);
    }
    prepare();
  }, []);

  const onLayoutRootView = useCallback(async () => {
    if (appIsReady) {
      // Hide the splash screen
      await SplashScreen.hideAsync();
    }
  }, [appIsReady]);

  if (!appIsReady) {
    return null;
  }

  return (
    <View onLayout={onLayoutRootView} style={{ flex: 1, justifyContent: "center", alignItems: "center" }}><Text>Hello Word!</Text> </View>
  );
}

Second solution:第二种解决方案:

There is also AppLoading component from Expo, but it seems to be deprecated. Expo也有AppLoading组件,但似乎已被弃用。 But it works, and here is an overview of how you would use it:但它是有效的,这里是您如何使用它的概述:

 expo install expo-app-loading
import AppLoading from "expo-app-loading";
import {View, Text} from "react-native"


export default function App() {
 const [isChecking, setIsChecking] = useState(true);

 const  asyncDoThings = async ()=>{
    // You do here all the fetching and checking process
 }

 if (isChecking) {
    return (
      <AppLoading
        startAsync={() => asyncDoThings()}
        onFinish={() => setIsChecking(false)}
        onError={console.warn}
      />
    );
  }

  return <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}><Text>Hello Word!</Text></View>
  
}

Additionnal solution:附加解决方案:

The section below is a special use case answering the above question:以下部分是回答上述问题的特殊用例:

import AppLoading from "expo-app-loading";
import {View} from "react-native"

const App = () => {

  const [selectedTheme, setSelectedTheme] = useState(themes.light)
  const [isChecking, setIsChecking] = useState(true);

  const changeTheme = async () =>{
    try {
      const theme = await AsyncStorage.getItem("MyTheme")
      if (theme === "dark"){
      setSelectedTheme(themes.nightSky)} 
      else if (theme === "light") {
        setSelectedTheme(themes.arctic)
        }
    } catch (err) {alert(err)}
  }
  
  if (isChecking) {
    return (
      <AppLoading
        startAsync={() =>   changeTheme()}
        onFinish={() => setIsChecking(false)}
        onError={console.warn}
      />
    );
  }
  
  return (
    <ThemeContext.Provider value={{selectedTheme, changeTheme}}>
         <NavigationContainer>
            <Stack.Navigator screenOptions={{headerShown:false, presentation: 'modal'}}>
              <Stack.Screen name="Home" component={home}/>
            </Stack.Navigator>
          </NavigationContainer>
    </ThemeContext.Provider>

  );
};

I had the same issue but in my case I have created an expo project with initial navigation screens.我遇到了同样的问题,但就我而言,我创建了一个带有初始导航屏幕的展览项目。 When you create a project with this setting, the App.tsx file will contain the hook useCachedResources.当您使用此设置创建项目时,App.tsx 文件将包含挂钩 useCachedResources。

import { StatusBar } from 'expo-status-bar';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import useCachedResources from './src/hooks/useCachedResources';
import Navigation from './src/navigation';
  
export default function App() {
  const isLoadingComplete = useCachedResources();
  if (!isLoadingComplete) {
    return null;
  } else {
    return (
      <SafeAreaProvider>
        <Navigation />
        <StatusBar />
      </SafeAreaProvider>
    );
  }
}

When checking the hook, we can see that there is a code to keep the splash screen while loading the fonts.检查钩子时,我们可以看到有一个代码可以在加载字体时保持启动画面。 So we just add the timeout on the finally block before the SplashScreen.hideAsync().所以我们只需在 SplashScreen.hideAsync() 之前的 finally 块中添加超时。

import { FontAwesome } from '@expo/vector-icons';
import * as Font from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';

export default function useCachedResources() {
  const [isLoadingComplete, setLoadingComplete] = useState(false);
  useEffect(() => {
    async function loadResourcesAndDataAsync() {
      try {
        SplashScreen.preventAutoHideAsync();
        await Font.loadAsync({
          ...FontAwesome.font,
          'space-mono': require('../assets/fonts/SpaceMono-Regular.ttf'),
        });
      } catch (e) {
        console.warn(e);
      } finally {
        await new Promise(resolve => setTimeout(resolve, 2000));
        setLoadingComplete(true);
        SplashScreen.hideAsync();
      }
    }
    loadResourcesAndDataAsync();
  }, []);
  return isLoadingComplete;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM