I have a custom animated tabbar component with react-native-reanimated. Im trying to implement it with react navigation but when i do the animation doesnt work. Any help to what to add for it to be functional. Here are the components Tab component
interface TabProps {
children: ReactElement;
onPress: () => void;
// navigation: NavigationStackScreenProps<any, any>;
active: Animated.Node<number>;
transition: Animated.Node<number>;
index: number;
label: string;
}
const styles = StyleSheet.create({
icon: {
overflow: 'hidden',
},
});
export default ({
children,
active,
transition,
index,
onPress,
}: TabProps) => {
const isActive = eq(active, index);
const activeTransition = withTransition(isActive, {duration: DURATION});
const isGoingLeft = greaterThan(transition, active);
const width = interpolateNode(activeTransition, {
inputRange: [0, 1],
outputRange: [0, ICON_SIZE],
});
const direction = cond(
isActive,
cond(isGoingLeft, 'rtl', 'ltr'),
cond(isGoingLeft, 'ltr', 'rtl'),
);
return (
<TouchableWithoutFeedback {...{onPress}}>
<Animated.View
style={{
width: ICON_SIZE,
height: ICON_SIZE,
direction
}}>
<View style={StyleSheet.absoluteFill}>{children}</View>
<Animated.View style={[styles.icon, {width}]}>
{cloneElement(children, {active: true})}
</Animated.View>
</Animated.View>
</TouchableWithoutFeedback>
);
};
TabBar index:
const tabs = [
{icon: <Home />, label: 'Home'},
{icon: <User />, label: 'Video'},
{icon: <Tv />, label: 'LiveStream'},
{icon: <Wallet />, label: 'Signin'},
];
const styles = StyleSheet.create({
container: {
backgroundColor: '#F0F0F6',
width: '90%',
position: 'absolute',
bottom: 20,
left: '5%',
borderRadius: 10,
},
tabs: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
tab: {
width: SEGMENT / 1.2,
height: ICON_SIZE + PADDING * 2,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
});
export default ({...props}) => {
const active = new Value<number>(0);
let navigation = useNavigation();
const transition = withTransition(active, {duration: DURATION});
const activeTransition = new Value(0);
useCode(
() =>
block([
onChange(active, set(activeTransition, 0)),
set(activeTransition, timing({duration: DURATION})),
]),
[active, activeTransition],
);
return (
<SafeAreaView style={styles.container}>
<View style={styles.tabs}>
{tabs.map(({icon, label}, index) => (
<View key={index} style={styles.tab}>
<Weave {...{active, transition, index}} />
<Tab
onPress={() => {
active.setValue(index);
console.log(active);
// title.setValue(label);
props.navigation.navigate(label);
}}
{...{active, transition, index, label}}>
{icon}
</Tab>
</View>
))}
<Particules {...{transition, activeTransition}} />
</View>
</SafeAreaView>
);
};
Here is the dribble example i was trying to copy https://dribbble.com/shots/5380015-WeChat-Tab-Bar-Redesign
What version of react-native-reanimated
and react-native
are you using?
There's a few things that I'm seeing that should be causing issues, but I'm also not entirely sure what's available for your versions.
The biggest thing I'm seeing is that you're instantiating new Value
objects on every render of the component, which should be causing issues if trying to animate in a functional way. Looking into react-native-reanimated
a little bit there appears to be a few hooks (useValue
and useSharedValue
) that should provide you with a consistent object that you can use where applicable. It looks like you'll want to use useValue
.
Since the animations are giving you troubles it may be a good idea to use the examples provided in their fundamentals as good reference for side-by-side comparison. This could be especially useful if you had/have it working as a class component to compare the differences. As well as their useAnimatedStyle
hook for how they handle animating in a functional component.
A few other items to note
timing
call to be withTiming
. timing
appears to be specific for v1set
you may want to useSharedValue
and just assign to the shared value's value
property. set
also appears to be specifically for v1 of reanimated// useSharedValue is provided by "react-native-reanimated"
const active = useSharedValue(0);
const activeTransition = useSharedValue(0);
// useEffect is provided by "react"
useEffect(() => {
// Set activeTransition to 0
activeTransition.value = 0;
}, [active.value]); // When active.value changes
Hopefully this helps