再來一個經典的導覽列。
自我檢測
- 我知道怎麼透過客製化元件來當作 NabBar
- 我知道怎麼把 Drawer 跟 Stack 結合起來用
- 我知道怎麼透過
options
來傳遞 props 給自定義元件
關於背後的設計理念
在不考慮太多的情況下,假設你想做的效果是這樣:
有一個側邊導覽列,可以進入 Home
跟 About
(順道一提,這個可以拉出來的東西就叫做「Drawer Navigation」,也是我們等一下要實作的東西。)
接著,Home
裡面又可以進入到其他頁面,像這樣:
而 About 的話就只是一個普通的頁面:
你可以先想想看,你會怎麼來實作這樣的東西?
會特別提這個的原因是,其實 Home
跟 About
這兩個頁面其實都是 Stack Navigation。
你可能會想說幹嘛不直接拿 About
來用就好,還要包成一個 Stack?回答這問題之前,不如直接來試試看,看結果會怎麼樣:
看到了吧,上面那條 NavBar 消失了,這個就是為什麼都還要包成 Stack 的原因:
就算只有一個頁面,我也希望他有上面的 NavBar
所以你才會看到很多人設計路由時都是這樣子:
總之希望這邊可以幫你解惑一點,因為等一下的範例也會用這種方式來實作。
需要裝的套件
我假設你目前已經有這些套件,沒有的話請順便裝起來:
- @react-navigation/native (npm) 核心
- @react-navigation/native-stack (npm) 建立 Stack 需要
- react-native-screens (expo) 給 Expo 用的
- react-native-safe-area-context (expo) 給 Expo 用的
接著是使用 Drawer Navigation 會用到的套件:
- @react-navigation/drawer (npm) 核心
- react-native-gesture-handler (expo) 給 Expo 用的
- react-native-reanimated (expo) 給 Expo 用的
動工吧!
這邊會延續 React Navigation-Navigation Stack 的概念來繼續往下做。目標是一開始展示的那種效果,所以就直接開始吧!
首先我們會有三個頁面,分別為:
Home
Detail
About
最開始的時候有說過,為了讓每個頁面都有 NavBar,所以會拆成兩個 Stack,分別是:
HomeStack
AboutStack
如果你忘記的話可以拉回去上面看一下藍圖,總之 Drawer Navigation 的任務就是負責顯示這兩個不同的 Stack!
所以第一步就是先建立好 Stack,這邊的東西你應該要看得懂,所以就不特別解釋了
1 | // HomeStack.tsx |
1 | // About.tsx |
到這邊 Stack 的部分就完成了,接下來是 Drawer 的部分。
但說實話,等一下要做的東西基本上就跟在做 Stack 時有 87 分像,你直接看 code 大概就能抓到那個 pattern 了:
1 | import { createDrawerNavigator } from "@react-navigation/drawer"; |
這邊解釋一下 screenOptions
的部分。
如果沒有設定 headerShown: false
,預設會顯示另一個 NavBar 像這樣:
至於 title
的部分就如同註解裡所說的,這部分就不再貼圖片了。
總之,做到這邊以後基本的 Drawer Navigation 就完成了。
還沒完,這時候你可能會碰到的 bug
把剛剛寫的 code 拿去執行後,你有可能會得到這個錯誤訊息:
Error: Reanimated 2 failed to create a worklet, maybe you forgot to add Reanimated’s babel plugin?
這邊爬了一段時間才找到解法,是參考 這篇 來解的。
簡單來說是跟 babel 有關的問題,詳細參考 官方文件 的說明,但總之呢,請先安裝這個東西:
1 | expo install react-native-reanimated |
接著去設定 babel.config.js
:
1 | module.exports = function(api) { |
接著用清除快取的方式來重啟 Expo:
1 | expo start --clear |
沒意外的話就能解決囉!
加上客製化的 Header!
先複習一下,在剛剛解完 bug 以後,你應該就會有這樣的效果:
看起來似乎還挺順利的,但必須老實説的是,如果沒有特別介紹的話一般人根本不知道有這個功能吧?畢竟一點提示都沒有RRRRR!
所以接下來我們要做的就是把他改成這樣子:
這邊我只會講個大概,不會講太細,因為用文字敘述的話有點麻煩。如果真的想要 Step-By-Step 的話,可以參考這個影片。
簡單來說,我們可以客製化一個元件,再把他透過 options
的方式放到 Screen 中(就像透過 title
來改變顯示文字一樣)。
附註:如果你後來發現有寬高無法填滿的問題的話,建議改用 header 來設定
所以我們要客制的元件內容如下:
1 | import { View, Text, StyleSheet, TouchableOpacity, StatusBar } from "react-native"; |
這邊我想特別講地方的只有一個,就是 container
的設定。
之所以會把寬高設為 100%
,是因為我們這個元件「會放在 Navbar 裡面」,所以會有「父子階層」的意思,所以這時候的 %
就會以 NavBar 來做計算。
不用想得太複雜,我們要的就是讓他填滿原本 NavBar 的寬跟高而已。
接著來看怎麼把他放到 options
中,不過要注意一件事情,我們要放的地方只會有兩個,一個是 Home
,一個是 About
。
為什麼 Detail
不用放?因為我們希望它保留原本的樣子,讓他保留那個 <back
的按鈕,所以它的部分不用做額外調整。
1 | import { createNativeStackNavigator } from "@react-navigation/native-stack"; |
這邊可以注意到兩個地方:
options
傳的是一個 function- 在
headerTitle
中傳的也是一個 function
先解釋第一個,這樣寫是因為我們想把 navigation
當作 props 傳入 <Header />
,所以才得這樣寫。
至於第二點是因為我們想要用客製元件來當作內容,所以一樣得透過 function 的方式來回傳 JSX。
以上,做到這邊後你就有一個比較優的 Drawer Navigation 囉!