iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 30
0
Modern Web

我不用Expo啦,React Native!系列 第 30

[Day30] 初始畫面:JS版

今日關鍵字:Splash Screen


初始畫面是點擊App後首先出現的畫面
(像是打開推特時那隻鳥會從標誌放大到整個畫面)

這個需要原生來處理
而今天先試著以別的方式來模仿這個效果

  • 原生:展現初始畫面後開始跑App
  • 模仿:開始跑App後首先展現初始畫面,再跳轉首頁

由於React Native內能處理到的地方最早只能從App開始跑的地方開始
所以再怎麼模仿跟原生的表現還是有所差別
如果很在意的話還是只能從原生下手


Stack

這裡需要多包一層Stack.Navigator

// App.tsx
const App = () => (
  <Provider store={store}>
    {/* <Navigation /> */}
    <NavigationContainer>
      <!--1.-->
      <Stack.Navigator headerMode="none">
        <Stack.Screen
          name="SplashScreen"
          options={() => ({ animationEnabled: false, headerShown: false })}
          component={SplashScreen}
        />
        <!--2.-->
        <Stack.Screen
          name="Navigation"
          options={() => ({ animationEnabled: false, headerShown: false })}
          component={Navigation}
        />
      </Stack.Navigator>
    </NavigationContainer>
  </Provider>
)

因為外面已經包了<NavigationContainer>,所以要移除Navigation裡的那個

// Navigation.tsx
...
  return (
    </>
    // <NavigationContainer>
...

這裡要注意的點有兩個

  1. <Stack.Navigator">需加上headerMode="none"
    有加
    https://ithelp.ithome.com.tw/upload/images/20200925/20121828i1jnlH7LbH.png
    沒加
    https://ithelp.ithome.com.tw/upload/images/20200925/2012182859an5I8PTM.png
    可以看到如果不去除header,會把下層的覆蓋過去

  2. { animationEnabled: false }
    <Stack.Screen>的options如果不取消預設的過場動畫,會有很明顯的換頁感
    跟期望的效果有所差別,當然這裡也可以調整transition達成自己喜歡的過場效果

初始畫面內容

最後把想要呈現的初始畫面寫出來
再以useEffect撰寫換頁條件就可以了
(我這裡是先打API拿到資料後才跳轉首頁)

import React, { useEffect } from 'react'
import { View, StyleSheet, Image, Text } from 'react-native'
import { useNavigation } from '@react-navigation/native'
import { useDispatch, useSelector } from 'react-redux'

import splashIcon from '../assets/splash_icon.png'
import { RootStateType } from '../redux/reducer/rootReducer'
import { getAllAnimeBegin } from '../redux/action/animeAction'
import { getLanguageBegin } from '../redux/action/languageAction'

const SplashScene = () => {
  const navigation = useNavigation()
  const dispatch = useDispatch()
  const allAnime = useSelector((state: RootStateType) => state.allAnime)

  useEffect(() => {
    dispatch(getLanguageBegin())
    dispatch(getAllAnimeBegin())
  }, [])

  useEffect(() => {
    if (allAnime.length > 0) {
      // @ts-ignore
      // navigation.replace('Navigation')
      navigation.reset({
        index: 0,
        routes: [
          {
            name: 'Navigation'
          }
        ]
      })
    }
  }, [allAnime])

  return (
    <View style={styles.container}>
      <Image source={splashIcon} />
      <Text style={styles.loading}>Loading...</Text>
    </View>
  )
}

這裡跳轉回首頁的方法不是之前一直在用的

navigation.navigate()

而是

navigation.replace()

或是

navigation.reset()

navigate()的操作類似於web的pushstate,會留下前一頁的紀錄
也就是當回到首頁後會出現上一頁的按鈕
https://ithelp.ithome.com.tw/upload/images/20200925/20121828byZErtoXEm.png
網路上有人說:可以把header藏起來就好
但這裡要注意的是,剛剛已經把上層的header藏起來了
下層的header也還是會有那個按鈕
把header藏起來的做法顯然是個治標不治本的做法

這裡有個奇怪的地方是
如果直接這樣用

navigation.replace(...)

會跳出錯誤
https://ithelp.ithome.com.tw/upload/images/20200925/20121828f6sXvd7ADJ.png

如果試著印出navigation
https://ithelp.ithome.com.tw/upload/images/20200925/20121828n8dP7j0xeI.png
的確有replace(),重要的是的確可以正常使用...
只能這樣了

// @ts-ignore
navigation.replace('Navigation')

摀住lint的嘴巴/images/emoticon/emoticon07.gif


明天改來試試看原生的Splash Screen


上一篇
[Day29] Build成App
下一篇
[Day31] 初始畫面:原生版
系列文
我不用Expo啦,React Native!33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言