我遇到了同样的问题,我需要向选项卡导航器添加一个与屏幕无关的自定义组件,但我尝试的一切都失败了。就我而言,我正在尝试使用 createMaterialTopTabNavigator。
React Navigation 5 的文档有点粗糙,没有很多 React Navigation 5 的示例,但经过多次尝试,我可以创建一个自定义组件并自己设置样式,这样我就可以混合路由创建的选项卡和自定义选项卡嵌入在选项卡导航器中的按钮。
import * as React from 'react';
import { View } from 'react-native'
import {
NavigationHelpersContext,
useNavigationBuilder,
TabRouter,
TabActions,
createNavigatorFactory,
} from '@react-navigation/native';
import styled from 'styled-components'
import Colors from '../constants/Colors';
const customTabNavigator = ({
initialRouteName,
children,
screenOptions,
tabContainerStyle,
contentStyle,
leftIcon,
rightIcon
}) => {
const { state, navigation, descriptors } = useNavigationBuilder(TabRouter, {
children,
screenOptions,
initialRouteName,
});
return (
<NavigationHelpersContext.Provider value={navigation}>
<OuterWrapper style={tabContainerStyle}>
{ leftIcon }
<TabWrapper>
{state.routes.map((route, i) => {
return (
<Tab
key={route.key}
onPress={() => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!event.defaultPrevented) {
navigation.dispatch({
...TabActions.jumpTo(route.name),
target: state.key,
});
}
}}
style={descriptors[route.key].options.tabStyle}
>
{ descriptors[route.key].options.label ?? <Label active={state.index === i}>{descriptors[route.key].options.title || route.name}</Label> }
</Tab>
)
})}
</TabWrapper>
{ rightIcon }
</OuterWrapper>
<View style={[{ flex: 1 }, contentStyle]}>
{descriptors[state.routes[state.index].key].render()}
</View>
</NavigationHelpersContext.Provider>
);
}
const OuterWrapper = styled.View`
height: 55px;
flex-direction: row;
justify-content: space-between;
background-color: ${Colors.grey1};
`
const TabWrapper = styled.View`
flex: 1;
flex-direction: row;
justify-content: space-evenly;
`
const Tab = styled.TouchableOpacity`
padding: 0 24px;
justify-content: center;
height: 100%;
`
const Label = styled.Text`
font-family: Futura-Medium;
font-size: 26px;
color: ${({ active }) => active ? Colors.grey6 : Colors.grey3};
`
export default createNavigatorFactory(customTabNavigator)
import customTabNavigator from './customTabNavigator'
import * as React from 'react';
import { View, Image } from 'react-native'
import {
ProjectsScreen,
RenderScreen,
EventsScreen,
CameraScreen
} from '../screens';
import Colors from '../constants/Colors'
import logo from '../assets/images/icon.png'
import { Ionicons } from '@expo/vector-icons';
import { TouchableOpacity } from 'react-native-gesture-handler';
const TopTab = customTabNavigator();
const INITIAL_ROUTE_NAME = 'Home';
export default function MainNavigator({ navigation, route }) {
navigation.setOptions({ headerTitle: getHeaderTitle(route) });
return (
<TopTab.Navigator
initialRouteName={INITIAL_ROUTE_NAME}
leftIcon={(
<TouchableOpacity style={{ height: "100%", justifyContent: "center" }} onPress={() => alert("Whatever")}>
<Image source={logo} style={{ resizeMode: "center", width: 70, height: 40 }} />
</TouchableOpacity>
)}
>
<TopTab.Screen
name="Home"
component={ProjectsScreen}
options={{
title: 'Proyectos',
}}
/>
<TopTab.Screen
name="Preview"
component={EventsScreen}
options={{
title: 'Eventos',
}}
/>
<TopTab.Screen
name="Render"
component={RenderScreen}
options={{
title: 'Mi cuenta',
}}
/>
<TopTab.Screen
name="Camera"
component={CameraScreen}
options={{
title: "Camera",
label: (
<View style={{ width: 36, height: 32, backgroundColor: Colors.grey3, borderRadius: 3, alignItems: "center", justifyContent: "center" }}>
<Ionicons name="md-camera" style={{ color: Colors.grey5 }} size={25} />
</View>
),
tabStyle: { flexDirection: "row", alignItems: "center", justifyContent: "flex-end", flex: 1 }
}}
/>
</TopTab.Navigator>
);
}
function getHeaderTitle(route) {
const routeName = route.state?.routes[route.state.index]?.name ?? INITIAL_ROUTE_NAME;
switch (routeName) {
case 'Home':
return 'Montar vídeo';
case 'Preview':
return 'Previsualizar vídeo';
case 'Render':
return 'Renderizar';
case 'Gallery':
return 'Galería'
case 'Camera':
return 'Camera'
}
}
对于https://reactnavigation.org/docs/custom-navigators的示例,我添加了不同的样式和两个新的道具,leftIcon 和 rightIcon。该道具接收一个组件,用于将其渲染到选项卡包装器的相应侧。并且这个组件可以是 TouchableWhatevers,带有与屏幕无关的自定义 onPress:P
我希望它有帮助,我几乎把自己从窗户扔出去,直到我成功了,哈哈