0

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

kxh
  • 59
  • 14

1 Answers1

1

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

  1. You may need to replace the timing call to be withTiming. timing appears to be specific for v1
  2. Rather than using set 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

SquEdgy
  • 101
  • 2
  • Also, as a side comment, if you're not familiar with hooks in react, it may be a good idea to look through the [react documentation relating to them](https://reactjs.org/docs/hooks-intro.html), or even just [their API](https://reactjs.org/docs/hooks-reference.html). – SquEdgy May 26 '22 at 13:46
  • Thank you for the information provided, i figured it out a couple of days ago about the useValue and stuff. Im working with the latest version of react native and reanimated 2. I will accept this as a valid answer and give you the bounty. Thanks once again and cheers – kxh May 26 '22 at 15:48