实现对现有动画标签栏的反应导航

Implement react navigation to an existing animated tabbar

我有一个带有 react-native-reanimated 的自定义动画标签栏组件。我试图通过反应导航来实现它但是当我做动画时不起作用。对添加内容以使其正常运行的任何帮助。 这是组件 选项卡组件

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>
  );
};

标签栏索引:

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>
  );
};

这是我试图复制的运球示例https://dribbble.com/shots/5380015-WeChat-Tab-Bar-Redesign

您使用的 react-native-reanimatedreact-native 是什么版本? 我发现有几件事应该会导致问题,但我也不完全确定哪些内容适用于您的版本。

我看到的最重要的事情是您在组件的每个渲染器上实例化新的 Value 对象,如果尝试以功能方式设置动画,这应该会导致问题。稍微研究 react-native-reanimated 似乎有一些挂钩 (useValue and useSharedValue) 应该为您提供一个一致的对象,您可以在适用的地方使用。看起来您需要使用 useValue.

由于动画会给您带来麻烦,因此使用 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 钩子来了解它们如何处理功能组件中的动画可能是个好主意。

其他一些注意事项

  1. 您可能需要将 timing 调用替换为 withTiming. timing 似乎特定于 v1
  2. 而不是使用 set,您可能想要 useSharedValue 并只分配给共享值的 value 属性。 set 似乎也专门针对 reanimated
  3. 的 v1
// 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

希望这对您有所帮助