如何使用React Navigation实现中间凸起的底部标签按钮?
你要实现的效果参考:
方案选择参考
- 方案1(定制第三个标签按钮):适合中间按钮点击后需要切换到对应Tab页面(也就是你的Premium页面)的场景,逻辑和原生Tab导航完全对齐,实现成本最低
- 方案2(4个标签+中间悬浮按钮):适合中间按钮点击后不切换Tab、而是弹出菜单/跳转独立页面的场景,灵活性更高
方案1 实现代码
无需改动现有Tab的数量结构,只需要给Tab.Navigator添加全局样式配置,给第三个Premium标签自定义按钮渲染逻辑即可:
import * as React from 'react'; import { Text, View, TouchableOpacity, StyleSheet, Platform } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; // 示例用图标库,可替换为自己的图标资源 import { Ionicons } from '@expo/vector-icons'; // 补全你的页面组件 function ForYouScreen() { return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>ForYou!</Text></View>; } function MapsScreen() { return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>Maps!</Text></View>; } function PremiumScreen() { return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>Premium!</Text></View>; } function ShopScreen() { return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>Shop!</Text></View>; } function MediaScreen() { return <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>Media!</Text></View>; } const Tab = createBottomTabNavigator(); export default function App() { return ( <NavigationContainer> <Tab.Navigator screenOptions={({ route }) => ({ // 隐藏头部 headerShown: false, // Tab栏基础样式 tabBarStyle: styles.tabBar, tabBarShowLabel: true, tabBarActiveTintColor: '#6200ee', tabBarInactiveTintColor: '#666', // 普通Tab的图标 tabBarIcon: ({ focused, color, size }) => { let iconName; if (route.name === 'ForYou') iconName = focused ? 'heart' : 'heart-outline'; else if (route.name === 'Maps') iconName = focused ? 'map' : 'map-outline'; else if (route.name === 'Shop') iconName = focused ? 'cart' : 'cart-outline'; else if (route.name === 'Media') iconName = focused ? 'play-circle' : 'play-circle-outline'; else if (route.name === 'Premium') iconName = focused ? 'star' : 'star-outline'; return <Ionicons name={iconName} size={route.name === 'Premium' ? 28 : size} color={color} />; }, })} > <Tab.Screen name="ForYou" component={ForYouScreen} /> <Tab.Screen name="Maps" component={MapsScreen} /> <Tab.Screen name="Premium" component={PremiumScreen} options={{ // 自定义凸起按钮 tabBarButton: ({ children, onPress }) => ( <TouchableOpacity style={styles.premiumButton} onPress={onPress} > {children} </TouchableOpacity> ), tabBarLabel: () => null, // 隐藏中间按钮的文字 }} /> <Tab.Screen name="Shop" component={ShopScreen} /> <Tab.Screen name="Media" component={MediaScreen} /> </Tab.Navigator> </NavigationContainer> ); } const styles = StyleSheet.create({ tabBar: { height: Platform.OS === 'ios' ? 85 : 65, paddingBottom: Platform.OS === 'ios' ? 20 : 10, paddingTop: 10, backgroundColor: '#fff', borderTopWidth: 1, borderTopColor: '#eee', }, premiumButton: { top: -20, justifyContent: 'center', alignItems: 'center', width: 60, height: 60, borderRadius: 30, backgroundColor: '#fff', shadowColor: '#6200ee', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 8, } });
方案2 实现代码
如果需要中间按钮不和Tab导航绑定,只做独立操作,就可以用4个Tab+中间悬浮按钮的方案:
- 首先把Tab的数量改为4个,左右各2个
- 自定义Tab栏的布局,给中间预留出悬浮按钮的位置
- 添加绝对定位的悬浮按钮覆盖在中间位置
// 其他导入和页面组件和上面一致 export default function App() { return ( <NavigationContainer> <Tab.Navigator screenOptions={{ headerShown: false, tabBarStyle: styles.tabBar, tabBarActiveTintColor: '#6200ee', tabBarInactiveTintColor: '#666', tabBarItemStyle: { width: '22%' }, // 四个Tab每个占22%宽度,剩下12%留作中间位置 }} > <Tab.Screen name="ForYou" component={ForYouScreen} /> <Tab.Screen name="Maps" component={MapsScreen} /> <Tab.Screen name="Shop" component={ShopScreen} /> <Tab.Screen name="Media" component={MediaScreen} /> </Tab.Navigator> {/* 中间悬浮按钮 */} <TouchableOpacity style={styles.floatButton} onPress={() => { // 自定义点击逻辑,比如弹出弹窗、跳转独立页面等 alert('点击了Premium按钮'); }} > <Ionicons name="star" size={28} color="#6200ee" /> </TouchableOpacity> </NavigationContainer> ); } const styles = StyleSheet.create({ tabBar: { height: Platform.OS === 'ios' ? 85 : 65, paddingBottom: Platform.OS === 'ios' ? 20 : 10, paddingTop: 10, paddingHorizontal: '2%', backgroundColor: '#fff', borderTopWidth: 1, borderTopColor: '#eee', }, floatButton: { position: 'absolute', bottom: Platform.OS === 'ios' ? 45 : 35, alignSelf: 'center', width: 60, height: 60, borderRadius: 30, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center', shadowColor: '#6200ee', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 8, } });
注意事项
- 所有样式数值可以根据你的设计稿灵活调整,凸起高度、圆角、图标大小、颜色都可以自定义
- 如果需要适配不同尺寸的设备,可以用
react-native-size-matters等库做响应式尺寸适配 - 图标可以直接替换为你自己的设计资源,不需要依赖第三方图标库
内容的提问来源于stack exchange,提问作者Guille Acosta
相关产品推荐
相关产品推荐

