【译】React Native Expo 教程(5) - 标签导航组件
翻 Tab navigation reactnavigation.org/docs/tab-ba… 译 RecoReco
移动应用中最常见的导航风格可能是基于标签的导航。这可以是屏幕底部的标签,也可以是页眉下方的顶部标签(甚至可以代替页眉)。
本指南介绍了createBottomTabNavigator。你也可以使用createMaterialBottomTabNavigator和createMaterialTopTabNavigator来为你的应用程序添加标签。
在继续之前,首先安装@react-navigation/bottom-tabs。
npm install @react-navigation/bottom-tabs
基于标签的最小导航示例
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
自定义外观
这类似于你如何定制堆栈导航器--有一些属性是在初始化标签导航器时设置的,还有一些属性可以在选项中按屏幕定制。
import Ionicons from 'react-native-vector-icons/Ionicons';
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused
? 'ios-information-circle'
: 'ios-information-circle-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
// You can return any component that you like here!
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
}}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
我们来剖析一下。
tabBarIcon是底部标签导航器中支持的一个选项。所以我们知道我们可以在我们的屏幕组件的属性中使用它,但在本例中选择把它放在Tab.Navigator的screenOptions属性中,以便集中配置图标,方便使用。
tabBarIcon是一个给定聚焦状态、颜色和大小参数的函数。如果你在配置中再往下看,你会看到tabBarOptions和activeTintColor和inactiveTintColor。这些默认为iOS平台的默认值,但你可以在这里更改它们。传递给tabBarIcon的颜色是活动或非活动的颜色。大小是标签栏所期望的图标大小。
阅读完整的API参考资料,了解更多关于createBottomTabNavigator配置选项的信息。
##在图标上添加徽章
有时我们想给一些图标添加徽章。一个常见的方法是使用一个额外的视图容器,并为徽章元素设置绝对定位的样式。
import * as React from 'react';
import { Text, View } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function IconWithBadge({ name, badgeCount, color, size }) {
return (
<View style={{ width: 24, height: 24, margin: 5 }}>
<Ionicons name={name} size={size} color={color} />
{badgeCount > 0 && (
<View
style={{
// On React Native < 0.57 overflow outside of parent will not work on Android, see https://git.io/fhLJ8
position: 'absolute',
right: -6,
top: -3,
backgroundColor: 'red',
borderRadius: 6,
width: 12,
height: 12,
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text style={{ color: 'white', fontSize: 10, fontWeight: 'bold' }}>
{badgeCount}
</Text>
</View>
)}
</View>
);
}
function HomeIconWithBadge(props) {
// You should pass down the badgeCount in some other ways like React Context API, Redux, MobX or event emitters.
return <IconWithBadge {...props} badgeCount={3} />;
}
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
if (route.name === 'Home') {
return (
<HomeIconWithBadge
name={
focused
? 'ios-information-circle'
: 'ios-information-circle-outline'
}
size={size}
color={color}
/>
);
} else if (route.name === 'Settings') {
return (
<Ionicons
name={focused ? 'ios-list-box' : 'ios-list'}
size={size}
color={color}
/>
);
}
},
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
}}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
在标签之间跳转
从一个标签切换到另一个标签有一个熟悉的API - navigation.navigate。
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<Button
title="Go to Settings"
onPress={() => navigation.navigate('Settings')}
/>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
);
}
每个标签的堆栈导航器
通常标签页并不只显示一个屏幕--例如,在你的Twitter feed上,你可以点击一条推文,它就会将你带到该标签页内的一个新屏幕,并显示所有的回复。你可以把它想象成每个标签页中都有单独的导航栈,这正是我们在React Navigation中的建模方式。
import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function DetailsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Details!</Text>
</View>
);
}
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
function SettingsScreen({ navigation }) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
const SettingsStack = createStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Settings" component={SettingsStackScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
为什么我们需要TabNavigator而不是TabBarIOS或其他组件?
试图使用一个独立的标签栏组件而不将其集成到你的应用程序中使用的导航库中是很常见的。在某些情况下,这样做很好! 然而当这样做时,您可能会遇到一些令人沮丧的意外问题。
例如,React Navigation的标签导航器为您处理Android后退按钮,而独立组件通常不会这样做。此外,如果你需要为它调用到两个不同的API,那么你(作为开发者)执行诸如 "跳转到这个标签页,然后转到这个屏幕"这样的操作就比较困难。
最后,移动用户界面有许多小的设计细节,要求某些组件能够意识到其他组件的布局或存在--例如,如果你有一个半透明的标签栏,内容应该在它下面滚动,滚动视图应该在底部有一个与标签栏高度相等的插页,这样你就可以看到所有的内容。双击标签栏应该使活动的导航堆栈弹到堆栈的顶部,再次这样做应该使该堆栈中的活动滚动视图滚动到顶部。虽然这些行为还没有全部在React Navigation中开箱即用,但它们会被实现,如果你使用独立的标签视图组件,你将不会得到任何这些。
转载自:https://juejin.cn/post/6855129008011477000