react native 如何实现这样的底部导航栏

340 天前
 owen800q

react navigation bottom tab 如何实现中间的 tab 凹下去,二维码在导航栏外

1078 次点击
所在节点    程序员
2 条回复
razor1895
340 天前
razor1895
340 天前
这是一个精简版本的实现

import { useEffect } from 'react';
import { Platform, StyleSheet, TouchableOpacity, View } from 'react-native';
import FastImage from 'react-native-fast-image';
import { trigger } from 'react-native-haptic-feedback';

import { BlurView } from '@react-native-community/blur';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { useQueryClient } from '@tanstack/react-query';

import { TAB_BAR_HEIGHT } from '@/styles';
import { p2d } from '@/utils';
import { pubsub } from '@/utils/pubsub';

import { Badge } from './Badge';

const TabBarIconMap = [
{
inactive: require('@/assets/icons/icon-crushes.png'),
active: require('@/assets/icons/icon-crushes-focused.png'),
style: {
width: p2d(24),
height: p2d(17),
},
},
{
inactive: require('@/assets/icons/icon-news.png'),
active: require('@/assets/icons/icon-news-focused.png'),
style: {
width: p2d(23),
height: p2d(18.596),
},
},
{
inactive: require('@/assets/icons/icon-confessions.png'),
active: require('@/assets/icons/icon-confessions-focused.png'),
style: {
width: p2d(18.35),
height: p2d(17),
},
},
{
inactive: require('@/assets/icons/icon-profile.png'),
active: require('@/assets/icons/icon-profile-focused.png'),
style: {
width: p2d(11),
height: p2d(17),
},
},
];

const TabBarIcon = ({
focused,
index,
tabBarBadge,
}: {
focused: boolean;
index: number;
tabBarBadge?: string | number;
}) => {
const map = TabBarIconMap[index];
return (
<View>
<FastImage
source={focused ? map.active : map.inactive}
style={map.style}
resizeMode='contain'
/>
<Badge visible={!!tabBarBadge} style={styles.badge}>
{tabBarBadge}
</Badge>
</View>
);
};

let showedInviteModal = false;

export function TabBar({ state, descriptors, navigation }: BottomTabBarProps) {
// @ts-ignore
const bottom = global.bottomInset || 0;
const queryClient = useQueryClient();

useEffect(() => {
const disposer = pubsub.subscribe('have_shown_swipe_modal', () => {
showedInviteModal = true;
});

return disposer;
}, []);

return (
<View style={[styles.container, { bottom: Math.max(bottom, 10) }]}>
{Platform.OS === 'ios' && (
<BlurView blurType='xlight' blurAmount={2} style={StyleSheet.absoluteFillObject} />
)}
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];

const isFocused = state.index === index;

const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
trigger('impactMedium');

if (!isFocused && !event.defaultPrevented) {
// The `merge: true` option makes sure that the params inside the tab screen are preserved
navigation.navigate({ name: route.name, merge: true });
}
};

return (
<TouchableOpacity
key={String(index)}
accessibilityRole='button'
accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={options.tabBarAccessibilityLabel}
testID={options.tabBarTestID}
onPress={onPress}
style={styles.item}
>
<TabBarIcon focused={isFocused} index={index} tabBarBadge={options.tabBarBadge} />
</TouchableOpacity>
);
})}
</View>
);
}

const styles = StyleSheet.create({
container: {
position: 'absolute',
// bottom: 0,
// left: 0,
height: TAB_BAR_HEIGHT,
flexDirection: 'row',
// backgroundColor: 'transparent',
backgroundColor: 'rgba(255,255,255,0.3)',
width: p2d(234),
alignSelf: 'center',
alignItems: 'center',
borderRadius: p2d(10),
overflow: 'hidden',
},
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
icon: {
width: p2d(18),
height: p2d(18),
},
badge: {
position: 'absolute',
right: p2d(-5),
top: p2d(-4),
},
});

自己实现 ui 即可

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/984700

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX