【问题标题】:React Native & Expo, how to control the splash screen?React Native和Expo,如何控制闪屏?
【发布时间】:2023-01-15 17:45:59
【问题描述】:

我正在使用您在 app.json 中添加的 expo 中的内置启动画面作为一个简单的测试应用程序。但是我注意到我的开始屏幕在显示我用 AsyncStorage 添加的资产之前以默认模式闪烁 1 毫秒。

我试过使用来自 expo 的splash-screen包 但我发现它有点混乱。有没有一种相当简单的方法来添加我的App.js这个逻辑:

显示启动画面,当所有资产都加载完毕后,加载此设置(使用我的上下文和屏幕),或者只是增加 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>

  );
};

【问题讨论】:

    标签: javascript reactjs react-native expo


    【解决方案1】:

    第一个解决方案

    您可以使用 Expo 的 SplashScreen 模块。以下是如何使用它的概述:

    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>
      );
    }
    

    第二种解决方案

    还有来自 Expo 的 AppLoading 组件,但它似乎已被弃用。但它确实有效,以下是您将如何使用它的概述:

     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>
      
    }
    

    加一个

    以下部分是使用AppLoading 回答上述问题的特殊用例。

    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>
    
      );
    };
    

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,但就我而言,我创建了一个带有初始导航屏幕的博览会项目。使用此设置创建项目时,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>
          );
        }
      }
      

      检查钩子时,我们可以看到有一段代码可以在加载字体时保持启动画面。所以我们只是在 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';
      
      SplashScreen.preventAutoHideAsync();
      
      export default function useCachedResources() {
        const [isLoadingComplete, setLoadingComplete] = useState(false);
        useEffect(() => {
          async function loadResourcesAndDataAsync() {
            try {
              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;
      }
      

      【讨论】:

      • 我认为这个答案要好得多。但是,我看不出将 TTI(交互时间)或应用程序启动延迟 2 秒的意义。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-29
      • 2018-08-20
      • 1970-01-01
      • 2020-03-11
      • 1970-01-01
      相关资源
      最近更新 更多