React Native 如何实现底部带弧度的复杂自定义 Tab Bar
React Native 带中心弧度凸起TabBar实现方案
实现思路
要做到响应式适配,核心是避免硬编码固定宽高数值,所有布局参数基于当前设备的屏幕尺寸、安全边距动态计算,弧度区域用SVG绘制适配不同屏幕宽度。
依赖准备
需要提前安装以下依赖:
- 导航相关:
@react-navigation/native、@react-navigation/bottom-tabs - SVG绘制相关:
react-native-svg、react-native-svg-transformer
安装完成后需要配置metro.config.js支持SVG导入,配置示例:
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); module.exports = mergeConfig(getDefaultConfig(__dirname), { transformer: { babelTransformerPath: require.resolve('react-native-svg-transformer'), }, resolver: { assetExts: getDefaultConfig(__dirname).resolver.assetExts.filter(ext => ext !== 'svg'), sourceExts: [...getDefaultConfig(__dirname).resolver.sourceExts, 'svg'], }, });
自定义TabBar核心实现
直接替换@react-navigation/bottom-tabs默认的TabBar组件,示例代码如下:
import { View, TouchableOpacity, Text, useWindowDimensions } from 'react-native'; import { Svg, Path } from 'react-native-svg'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; const ArcTabBar = ({ state, descriptors, navigation }) => { // 动态获取当前屏幕宽度,适配横竖屏、不同尺寸设备 const { width: screenWidth } = useWindowDimensions(); // 获取底部安全边距,适配全面屏、非全面屏设备 const { bottom: bottomInset } = useSafeAreaInsets(); const tabBarBaseHeight = 60; const tabBarTotalHeight = tabBarBaseHeight + bottomInset; const centerBulgeHeight = 22; // 中心凸起高度可自定义 // 基于屏幕宽度动态计算SVG弧度路径 const tabBarPath = ` M0,0 L${screenWidth/2 - 55},0 Q${screenWidth/2 - 30},0 ${screenWidth/2 - 25},${centerBulgeHeight} Q${screenWidth/2},${centerBulgeHeight * 2} ${screenWidth/2 + 25},${centerBulgeHeight} Q${screenWidth/2 + 30},0 ${screenWidth/2 + 55},0 L${screenWidth},0 L${screenWidth},${tabBarTotalHeight} L0,${tabBarTotalHeight} Z `; return ( <View style={{ position: 'absolute', bottom: 0, width: screenWidth }}> {/* 绘制带弧度的TabBar背景 */} <Svg width={screenWidth} height={tabBarTotalHeight} style={{ position: 'absolute' }}> <Path d={tabBarPath} fill="#ffffff" shadowColor="#000000" shadowOffset={{ width: 0, height: -3 }} shadowOpacity={0.12} shadowRadius={5} /> </Svg> {/* 渲染Tab按钮 */} {state.routes.map((route, index) => { const isCenterTab = index === Math.floor(state.routes.length / 2); const tabWidth = screenWidth / state.routes.length; return ( <TouchableOpacity key={route.key} style={{ position: 'absolute', top: isCenterTab ? -centerBulgeHeight : 12, left: tabWidth * index + tabWidth/2 - 24, alignItems: 'center', paddingBottom: isCenterTab ? 0 : bottomInset }} onPress={() => navigation.navigate(route.name)} > {/* 此处替换为你自己的Tab图标、文字即可 */} <Text style={{ color: state.index === index ? '#2563eb' : '#64748b' }}> {route.name} </Text> </TouchableOpacity> ) })} </View> ) } // 导航中使用自定义TabBar import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; const Tab = createBottomTabNavigator(); const AppNavigator = () => { return ( <Tab.Navigator tabBar={props => <ArcTabBar {...props} />}> {/* 配置你的Tab页面 */} <Tab.Screen name="首页" component={HomeScreen} /> <Tab.Screen name="分类" component={CategoryScreen} /> <Tab.Screen name="发布" component={PublishScreen} /> <Tab.Screen name="消息" component={MessageScreen} /> <Tab.Screen name="我的" component={MineScreen} /> </Tab.Navigator> ) }
适配注意事项
- 所有尺寸参数都基于动态获取的屏幕宽度、安全边距计算,无需适配不同设备的硬编码数值
- 如需适配横竖屏切换,无需额外处理,
useWindowDimensions会自动监听宽度变化更新路径 - 弧度的弯曲程度可以通过调整Path路径里的贝塞尔曲线参数自定义,调整到和设计图一致即可
内容的提问来源于stack exchange,提问作者SoF
相关产品推荐
相关产品推荐

