react-navigation自定义DrawerNavigator:如何设置DrawerItem激活/非激活背景色
自定义DrawerItem激活/非激活样式的实现方案
样式不生效的核心原因
- API版本不兼容:从
@react-navigation/drawerv6版本开始,旧的drawerContentOptions配置项已被完全废弃移除,无法对组件产生任何配置作用,原有的activeTintColor、activeBackgroundColor等参数已迁移到screenOptions的drawer前缀配置项中。 - 自定义组件的传参逻辑错误:你的
CustomDrawerContent组件写法function CustomDrawerContent({ props, navigation })存在解构错误——父组件传递的整个对象本身就是抽屉渲染所需的props(包含navigation、路由状态、默认样式配置等),不存在嵌套的props属性,导致后续给DrawerItem传递{...props}时根本拿不到有效状态数据。 - 动态渲染的条目无内置激活判断:你基于redux中的outlet数据循环渲染的
DrawerItem不属于与Drawer.Screen绑定的系统路由项,不会自动携带isFocused激活状态,就算配置了全局样式,系统也无法识别哪个条目应该应用激活样式。
分步实现自定义样式
1. 全局配置默认抽屉样式(替代旧的drawerContentOptions)
将原来写在drawerContentOptions里的配置迁移到Drawer.Navigator的screenOptions中,作为所有绑定路由的DrawerItem的默认样式:
<Drawer.Navigator // 替代旧drawerContentOptions的全局样式配置 screenOptions={{ drawerActiveTintColor: '#fff', // 激活状态文字色 drawerActiveBackgroundColor: '#68f', // 激活状态背景色 drawerInactiveTintColor: 'grey', // 非激活状态文字色 drawerInactiveBackgroundColor: 'transparent' // 非激活状态背景 }} drawerContent={(props) => <CustomDrawerContent {...props} />} initialRouteName="Home" > <Drawer.Screen name="Home" component={Home} /> </Drawer.Navigator>
2. 修正自定义抽屉组件的逻辑错误
- 修正组件的props接收方式,不再错误嵌套解构
props属性 - 针对动态渲染的outlet条目,结合redux中存储的选中状态手动判断激活态,绑定对应样式
修正后的CustomDrawerContent核心逻辑:
// 错误写法修正:直接接收props对象,不再嵌套解构props属性 function CustomDrawerContent(props) { const dispatch = useDispatch(); const navigation = props.navigation; const outlets = useSelector((state) => state.homeReducer.outlets); const defaultOutLet = useSelector((state) => state.homeReducer.defaultOutLet); const drawerItems = outlets.map((outlet) => { // 手动判断当前条目是否为激活状态 const isItemActive = defaultOutLet?.userCompanyId === outlet.userCompanyId; return ( <DrawerItem key={outlet.userCompanyId} label={outlet.name} // 手动绑定激活/非激活样式 labelStyle={{ color: isItemActive ? '#fff' : 'grey' }} style={{ backgroundColor: isItemActive ? '#68f' : 'transparent' }} onPress={() => { dispatch(homeActions.changeSelectedOutlet(outlet)); navigation.closeDrawer(); }} /> ); }); // 原有头部、分割线、退出按钮的UI逻辑保持不变 return ( <View style={styles.flexView}> <View style={styles.container}> <Image style={styles.image} source={Images.icons.logo} resizeMode="contain" /> {defaultOutLet && <Text style={styles.text}>{defaultOutLet.name}</Text>} </View> <View style={styles.separator} /> <View style={styles.flexView}>{drawerItems}</View> <View style={styles.separator} /> <View style={styles.bottomView}> <TouchableOpacity style={styles.logoutContainer} onPress={() => { dispatch(homeActions.clearUserCompany()); dispatch(loginActions.completeLogOutClearingUserData()); }}> <Image style={styles.logoutIcon} source={Images.icons.power} resizeMode="center" /> <Text style={styles.logoutText}>{i18n.t('common.logout')}</Text> </TouchableOpacity> </View> </View> ); }
3. 关键注意事项
- 不要给动态渲染的非路由类
DrawerItem传递{...props},这些props是系统为自动生成的路由条目准备的状态数据,强行传递可能导致样式错乱、状态判断异常。 - 如果你需要保留系统自动识别的路由激活态(比如绑定
Drawer.Screen的Home、Notifications页面),不要拦截props的正常传递,系统会自动根据当前路由的聚焦状态应用全局配置的激活/非激活样式。 - 对于所有非路由类的自定义条目(比如你的outlet列表),必须手动维护激活态的判断逻辑,系统不会自动为这类条目匹配激活样式。
内容的提问来源于stack exchange,提问作者Pasindu Weerakoon
相关产品推荐
相关产品推荐

