提问人:maggyy 提问时间:11/6/2023 最后编辑:maggyy 更新时间:11/6/2023 访问量:59
React 原生导航底部标签,浮动标签栏位于屏幕内容上方
React native navigation bottom tabs, floating tab bar is over the screen content
问:
我正在使用 React Native 和 React Navigation,并使用 position: 'absolute' 将底部标签栏设置为浮动。我还在外容器上设置了一个透明的背景,这样我就可以看到它后面的内容。但是,我面临着一个问题,即屏幕内容呈现在选项卡栏后面,使其无法访问。
为了解决这个问题,我尝试将 paddingBottom 添加到内容容器中,但随后在它应该保持透明的位置出现了灰色背景。看来我无法同时获得填充和透明效果。我已经广泛搜索,但没有找到解决方案。这是我代码的相关部分:
MainTabs.js
const Tab = createBottomTabNavigator();
const ICON_SIZE = 16;
const ICON_SIZE_FOCUSED = 24;
const ADDITIONAL_PADDING = 10;
const SIZE_DIFFERENCE = (ICON_SIZE_FOCUSED - ICON_SIZE) / 2 + ADDITIONAL_PADDING;
const MainTabs = () => {
const startup = useSelector(state => state.globalPersist?.startup);
const mainMenu = useMemo(() => startup?.mainMenu || {}, [startup]);
const tabBar = props => (
<CustomTabBar {...props} getAccessibilityLabel={({route}) => getTabBarAccessibilityLabel(route.name)} />
);
return (
<Tab.Navigator
tabBar={tabBar}
tabBarOptions={{
activeTintColor: NASColors.red,
keyboardHidesTabBar: true,
style: {
position: 'absolute',
marginBottom: 100,
bottom: 100,
},
}}
screenOptions={({route}) => ({
tabBarAccessibilityLabel: getTabBarAccessibilityLabel(route.name),
tabBarTestID: route.name,
title: route.name,
style: {
position: 'absolute',
marginBottom: 150,
bottom: 100,
},
tabBarIcon: ({color, focused}) => <TabBarIconComponent route={route} color={color} focused={focused} />,
})}>
<Tab.Screen
name={ScreenNames.MyTravels}
component={MyTravelsStackScreen}
options={{tabBarLabel: mainMenu?.[0]?.text}}
/>
<Tab.Screen
name={ScreenNames.Book}
component={BookStackScreen}
options={{
tabBarLabel: mainMenu?.[1]?.text,
}}
/>
<Tab.Screen
name={ScreenNames.Profile}
component={ProfileStackScreen}
options={{
tabBarLabel: mainMenu?.[2]?.text,
}}
/>
<Tab.Screen
name={ScreenNames.More}
component={MoreStackScreen}
options={{
tabBarLabel: mainMenu?.[3]?.text,
}}
/>
</Tab.Navigator>
);
};
const TabBarIconComponent = ({route, color, focused}) => {
const iconMapping = {
[ScreenNames.MyTravels]: SvgIcons.MyTravels,
[ScreenNames.Book]: SvgIcons.Search,
[ScreenNames.Profile]: SvgIcons.Profile,
[ScreenNames.More]: SvgIcons.Dots,
};
const IconComponent = iconMapping[route.name];
if (!IconComponent) {
return null;
}
return (
<View style={focused ? {paddingTop: SIZE_DIFFERENCE} : {}}>
<IconComponent
color={color}
width={focused ? ICON_SIZE_FOCUSED : ICON_SIZE}
height={focused ? ICON_SIZE_FOCUSED : ICON_SIZE}
/>
</View>
);
};
export default MainTabs;
自定义标签栏.js
const TabButton = ({route, descriptors, isFocused, handleTabPress}) => {
const {options} = descriptors[route.key];
const label = options.tabBarLabel || options.title || route.name;
return (
<TouchableOpacity
key={route.key}
onPress={() => handleTabPress(isFocused, route)}
style={styles.tabButton}
accessibilityRole="button"
accessibilityLabel={label}
{...testID(route.name)}
accessibilityState={{selected: isFocused}}>
{options?.tabBarIcon?.({
focused: isFocused,
color: isFocused ? NASColors.red : NASColors.blue,
})}
<Text style={[styles.label, {color: isFocused ? NASColors.transparent : NASColors.blue}]}>{label}</Text>
</TouchableOpacity>
);
};
const FocusedLine = ({tabWidth, animatedValue, state, padding, containerWidth}) =>
tabWidth > 0 && (
<Animated.View
style={[
styles.focusedLine,
{
width: tabWidth * 0.6,
transform: [
{
translateX: animatedValue.interpolate({
inputRange: [0, state.routes.length - 1],
outputRange: [padding + tabWidth * 0.2, containerWidth - tabWidth * 0.8 - padding],
}),
},
],
},
]}
/>
);
const CustomTabBar = ({state, descriptors, navigation}) => {
const isKeyboardVisible = useKeyboardVisibility();
const animatedValue = useRef(new Animated.Value(state.index)).current;
const [tabWidth, setTabWidth] = useState(0);
const [containerWidth, setContainerWidth] = useState(0);
const padding = 10;
useEffect(() => {
requestAnimationFrame(() => {
Animated.timing(animatedValue, {
toValue: state.index,
duration: 400,
easing: Easing.bezier(0.23, 1, 0.32, 1),
useNativeDriver: true,
}).start();
});
}, [animatedValue, state.index]);
const handleTabPress = (isFocused, route) => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!event.defaultPrevented) {
if (isFocused) {
navigation.popToTop();
} else {
navigation.navigate(route.name);
}
}
};
const onLayout = event => {
const {width} = event.nativeEvent.layout;
setContainerWidth(width);
setTabWidth((width - padding * 2) / state.routes.length);
};
if (isKeyboardVisible) return null;
return (
<View style={styles.outerContainer}>
<LinearGradient
colors={['rgba(241, 241, 241, 0)', 'rgba(241, 241, 241, 0.90)']}
start={{x: 0.1, y: 0}}
end={{x: 0.1, y: 0.2}}
style={styles.gradientOverlay}
/>
<View style={styles.innerContainer} onLayout={onLayout}>
{state.routes.map((route, index) => (
<TabButton
key={route.key}
route={route}
descriptors={descriptors}
isFocused={state.index === index}
handleTabPress={handleTabPress}
/>
))}
<FocusedLine
tabWidth={tabWidth}
animatedValue={animatedValue}
state={state}
padding={padding}
containerWidth={containerWidth}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
outerContainer: {
flexDirection: 'row',
position: 'absolute',
justifyContent: 'center',
paddingLeft: 10,
paddingRight: 10,
paddingBottom: 15,
width: '100%',
height: 100,
bottom: 0,
},
innerContainer: {
backgroundColor: NASColors.white,
borderRadius: 4,
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
padding: 10,
width: '97%',
alignSelf: 'center',
height: 65,
},
gradientOverlay: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 125,
},
tabButton: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
focusedLine: {
position: 'absolute',
alignSelf: 'center',
top: 50,
height: 4,
borderRadius: 1,
backgroundColor: NASColors.blue,
},
label: {
marginTop: 5,
fontSize: 12,
fontWeight: NASFontWeights.Medium,
},
});
export default CustomTabBar;
答: 暂无答案
评论