import React, {memo, useMemo, useCallback} from 'react'; import {View, TouchableOpacity} from 'react-native'; import Animated, { useDerivedValue, useAnimatedStyle, useAnimatedReaction, useSharedValue, } from 'react-native-reanimated'; import isEqual from 'react-fast-compare'; import type {TabBarItemProps} from '../../types'; import {sharedRound, sharedTiming, useInterpolate} from '../../AnimatedHelper'; import {styles} from './style'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; const ButtonTabItemComponent = (props: TabBarItemProps) => { // props const { index, selectedIndex, countTab, indexAnimated, width, icon, renderTitle, title, titleShown, focused, } = props; // reanimated const {bottom} = useSafeAreaInsets(); const isActive = useDerivedValue(() => sharedRound(indexAnimated.value)); const progress = useSharedValue(0); const opacity = useInterpolate(progress, [0, 0.8], [1, 0]); const translateY = useInterpolate(progress, [0, 0.4], [0, 10]); const scale = useInterpolate(progress, [0, 1], [1, 0.5]); // func const _onPress = useCallback(() => { selectedIndex.value = index; }, [index, selectedIndex]); // effect useAnimatedReaction( () => isActive.value === index, (result, prevValue) => { if (result !== prevValue) { progress.value = sharedTiming(result ? 1 : 0); } }, ); // reanimated style const containerIconStyle = useAnimatedStyle(() => ({ opacity: opacity.value, justifyContent: 'center', alignItems: 'center', transform: [ { translateY: translateY.value, }, ], })); const titleStyle = useAnimatedStyle(() => ({ transform: [{scale: scale.value}], })); const buttonTab = useMemo( () => ({ width: width / countTab, paddingBottom: bottom, }), [width, countTab, bottom], ); // render const renderIcon = useCallback(() => { return icon({progress, focused}); }, [focused, icon, progress]); const _renderTitle = useCallback(() => { return renderTitle?.({progress, focused, title: title ?? ''}); }, [focused, progress, renderTitle, title]); const showTitle = useCallback(() => { if (typeof renderTitle === 'function') { return _renderTitle(); } return ( <Animated.Text style={[styles.title, titleStyle]} allowFontScaling={false} numberOfLines={1}> {title ?? ''} </Animated.Text> ); }, [_renderTitle, renderTitle, title, titleStyle]); // render return ( <TouchableOpacity onPress={_onPress} activeOpacity={0.7}> <View style={[styles.buttonTab, buttonTab]}> <Animated.View style={[containerIconStyle]}> {renderIcon()} {titleShown ? showTitle() : null} </Animated.View> </View> </TouchableOpacity> ); }; export const ButtonTab = memo(ButtonTabItemComponent, isEqual);