支援安全範圍
React Navigation 預設會試著確保導覽列的元素能正確顯示在有缺口的裝置(例如 iPhone X)和可能會遮住應用程式內容的使用者介面元素上。這些項目包括
- 實體缺口
- 狀態列覆蓋區
- iOS 上的原點活動指示器
- Android 上的導覽列
沒有被這些項目覆蓋到的區域稱為「安全範圍」。
我們會試圖對導覽列的使用者介面元素套用正確的內縮,以避免被這些項目覆蓋。目標是(a)最大化畫面的使用(b)在沒有被實體顯示切割或作業系統使用者介面遮住的情況下隱藏內容或讓內容難以互動。
雖然 React Navigation 預設會為內建使用者介面元素處理安全範圍,但您的自訂內容可能也需要處理它,以確保內容不會被這些項目隱藏。
令人動心的是通過包裝一個帶有內距的容器(確保不會遮擋所有內容)到您的整個應用程式來解決 (a)。但這麼做會浪費掉屏幕上的大量空間,如下方左側的圖片所示。理想的情況下,我們想要的是右側的圖片。
雖然 React Native 匯出了一個 SafeAreaView
組件,但此組件僅支援 iOS 10 及以上版本,不支援舊版本的 iOS 或 Android。此外,它還有一些問題,例如:如果包含安全區域的屏幕正在動畫處理,它會導致跳動行為。因此,我們建議使用 useSafeAreaInsets
鉤子,從 react-native-safe-area-context 函式庫中以更可靠的方式處理安全區域。
react-native-safe-area-context
函式庫還匯出了一個 SafeAreaView
組件。儘管它可以在 Android 上工作,但在動畫處理時它也會遇到同樣與跳動行為相關的問題。所以我們建議始終使用 useSafeAreaInsets
鉤子,避免使用 SafeAreaView
組件。
本指南的其餘部分提供了有關如何支援 React Navigation 中安全區域的更多資訊。
隱藏/自訂標題或分頁標籤欄
React Navigation 在預設標題中處理安全區域。但是,如果您正在使用自訂標題,則確保您的 UI 位於安全區域內非常重要。
例如,如果我不為 header
或 tabBar
渲染任何內容,則什麼都不會渲染
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
function Demo() {
return (
<View
style={{ flex: 1, justifyContent: 'space-between', alignItems: 'center' }}
>
<Text>This is top text.</Text>
<Text>This is bottom text.</Text>
</View>
);
}
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator
initialRouteName="Home"
screenOptions={{ headerShown: false }}
>
<Stack.Screen name="Home">
{() => (
<Tab.Navigator
initialRouteName="Analitics"
tabBar={() => null}
screenOptions={{ headerShown: false }}
>
<Tab.Screen name="Analitics" component={Demo} />
<Tab.Screen name="Profile" component={Demo} />
</Tab.Navigator>
)}
</Stack.Screen>
<Stack.Screen name="Settings" component={Demo} />
</Stack.Navigator>
</NavigationContainer>
);
}
為了解決此問題,您可以在您的內容上套用安全區域內距。這可以使用來自 react-native-safe-area-context
函式庫的 useSafeAreaInsets
鉤子來實現
import {
SafeAreaProvider,
useSafeAreaInsets,
} from 'react-native-safe-area-context';
function Demo() {
const insets = useSafeAreaInsets();
return (
<View
style={{
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
// Paddings to handle safe area
paddingTop: insets.top,
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
}}
>
<Text>This is top text.</Text>
<Text>This is bottom text.</Text>
</View>
);
}
export default function App() {
return (
<SafeAreaProvider>
<NavigationContainer>{/*(...) */}</NavigationContainer>
</SafeAreaProvider>
);
}
請務必按照 這裡 的說明將您的應用程式包裝在 SafeArea提供者
中。
這將檢測應用程式是在具有缺口的裝置上執行,如果是,則確保內容不會隱藏在任何硬體元件後面。
橫向模式
即使您正在使用預設導覽列和分頁標籤欄 - 如果您的應用程式在橫向模式下工作,確保您的內容不會隱藏在感測器群組後面非常重要。
為了解決此問題,您還可以再次將安全區域內距套用至您的內容。這不會與導覽列或分頁標籤欄在直向模式下的預設行為衝突。
使用鉤子進行更多控制
在某些情況下,您可能需要對套用哪個填補有更多控制。例如,您只能透過變更style
物件來套用頂端和底端的填補
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function Demo() {
const insets = useSafeAreaInsets();
return (
<View
style={{
paddingTop: insets.top,
paddingBottom: insets.bottom,
flex: 1,
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<Text>This is top text.</Text>
<Text>This is bottom text.</Text>
</View>
);
}
類似地,您可以在FlatList
的contentContainerStyle
套用這些填補,讓內容避開安全區域,但在捲動時仍顯示在狀態列和導覽列底下。
摘要
- 使用
react-native-safe-area-context
中的useSafeAreaInsets
鉤子,而不是SafeAreaView
元件 - 不要將您的整個應用程式封裝在
SafeAreaView
中,而是套用樣式在畫面的內容內。 - 僅套用特定的插入,使用
useSafeAreaInsets
鉤子進行更多控制。