You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用react-native-reanimated时,如何适配期望Animated.Value的分页组件prop?

问题:Reanimated SharedValue 转 Animated.Value 适配分页点组件

我基于react-native-reanimated实现了一个Hook,用来捕获react-native-pager-view的滚动位置:

import { useEvent, useHandler } from 'react-native-reanimated';

import { AnimatedPagerScrollHookParams } from './animated-pager-scroll.type';

const useAnimatedPagerScroll = (
  handlers: AnimatedPagerScrollHookParams['handlers'],
  dependencies?: AnimatedPagerScrollHookParams['dependencies'],
) => {
  const { context, doDependenciesDiffer } = useHandler(handlers, dependencies);

  return useEvent(
    event => {
      'worklet';
      const { onPageScroll } = handlers;

      if (
        onPageScroll &&
        (
          event as {
            eventName: string;
          }
        ).eventName.endsWith('onPageScroll')
      ) {
        onPageScroll(event, context);
      }
    },
    ['onPageScroll'],
    doDependenciesDiffer,
  );
};

export default useAnimatedPagerScroll;

在PagerView组件中的使用方式如下:

<AnimatedPagerView
  onPageScroll={handler}
  style={{ flex: 1 }}
  initialPage={0}
>
  {slides.map((slide, index) => (
    <View
      key={index}
      style={{
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <ImageBackground
        testID="TestID__image-Onboarding"
        source={slide.imageUrl}
        style={{
          width: '100%',
          height: '100%',
          justifyContent: 'flex-end',
        }}
      >
        <LinearGradient
          colors={['rgba(255,255,255,1)', 'rgba(255,255,255,0)']}
          style={{
            position: 'absolute',
            left: 0,
            right: 0,
            top: 0,
            height: '50%',
          }}
        />
        <Typography
          testID="TestID__subtitle-Onboarding"
          variant="h1"
          color="alternateBasic"
          style={{
            marginBottom: 146,
            marginLeft: 43,
            width: index === slides.length - 1 ? '45%' : '35%',
          }}
        >
          {slide.subtitle}
        </Typography>
      </ImageBackground>
    </View>
  ))}
</AnimatedPagerView>

现在需要配合react-native-animated-pagination-dots库实现分页动画,但该库的scrollX属性要求传入Animated.Value类型,而我当前使用的是Reanimated的SharedValue,直接传入会触发类型错误。


解决方案

方法一:使用Reanimated内置转换方法(推荐,Reanimated 2.3+支持)

Reanimated提供了convertSharedValueToAnimatedValue方法,可以直接将SharedValue转换为Animated.Value,无需手动同步。

修改分页组件的使用代码:

import { convertSharedValueToAnimatedValue } from 'react-native-reanimated';

// ...其他代码

// 将SharedValue转换为Animated.Value
const animatedScrollX = convertSharedValueToAnimatedValue(translationY.value);

<ExpandingDot
  data={slides}
  expandingDotWidth={30}
  scrollX={animatedScrollX}
  inActiveDotOpacity={0.6}
  dotStyle={{
    width: 10,
    height: 10,
    backgroundColor: '#347af0',
    borderRadius: 5,
    marginHorizontal: 5,
  }}
  containerStyle={{
    top: 30,
  }}
/>

方法二:手动同步SharedValue到Animated.Value(兼容旧版本)

如果你的Reanimated版本较低不支持上述方法,可以使用useAnimatedReaction监听SharedValue的变化,手动同步到Animated.Value中。

修改分页组件的使用代码:

import { useAnimatedReaction } from 'react-native-reanimated';
import { Animated } from 'react-native';
import { useRef } from 'react';

// ...其他代码

// 创建Animated.Value实例
const animatedScrollX = useRef(new Animated.Value(0)).current;

// 监听SharedValue变化,同步到Animated.Value
useAnimatedReaction(
  () => translationY.value,
  (newValue) => {
    animatedScrollX.setValue(newValue);
  },
  [animatedScrollX]
);

<ExpandingDot
  data={slides}
  expandingDotWidth={30}
  scrollX={animatedScrollX}
  inActiveDotOpacity={0.6}
  dotStyle={{
    width: 10,
    height: 10,
    backgroundColor: '#347af0',
    borderRadius: 5,
    marginHorizontal: 5,
  }}
  containerStyle={{
    top: 30,
  }}
/>

内容的提问来源于stack exchange,提问作者shet_tayyy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:30:53