V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
owen800q
V2EX  ›  程序员

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

  •  
  •   owen800q · 2023-10-24 00:13:29 +08:00 · 1129 次点击
    这是一个创建于 401 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    Screenshot 2023-10-24 at 12.06.30 AM.png

    2 条回复    2023-10-24 00:30:37 +08:00
    razor1895
        2
    razor1895  
       2023-10-24 00:30:37 +08:00
    这是一个精简版本的实现

    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 即可
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5030 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 09:47 · PVG 17:47 · LAX 01:47 · JFK 04:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.