使用react-native-reanimated时,如何适配期望Animated.Value的分页组件prop?
我基于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
相关产品推荐
相关产品推荐

