这是一个精简版本的实现
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 即可