在重新动画的滚动视图上对 contentOffset 属性进行动画处理会在动画运行时禁用所有手势,包括 IOS 上的触摸事件。动画本身工作正常,一旦取消动画,触摸事件就会再次开始工作。在 Android 上一切正常。
重要包裹:
"expo": "^51.0.18",
"expo-router": "~3.5.17",
"react-native-gesture-handler": "~2.16.1",
"react-native-reanimated": "~3.10.1",
_layout.tsx:
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<GestureHandlerRootView style={{ flex: 1 }}>
...omitted
</GestureHandlerRootView>
</PersistGate>
</Provider>
);
ScrollView组件:
const offsetX = useSharedValue<number>(0);
const animatedProps = useAnimatedProps(() => ({
contentOffset: {
x: offsetX.value,
y: 0
}
}));
useEffect(() => {
offsetX.value = withRepeat(withTiming(getOffsetXEndPosition() , { duration: 25000, easing: Easing.linear }), -1, true);
}, [xxx]);
<Animated.ScrollView
onTouchStart={() => cancelAnimation(offsetX)}
animatedProps={animatedProps}
horizontal
showsHorizontalScrollIndicator={false}
>
...omitted
</Animated.ScrollView>
它专门添加了像“withTiming”或“withSpring”这样的动画,导致手势被禁用。直接设置偏移值就可以了。
更新: 我发现问题是因为动画滚动视图嵌套在另一个滚动视图内。删除外部滚动视图将重新启用触摸事件。不幸的是,它不是删除外部滚动视图的选项,我仍然不知道如何修复它:
<ScrollView style={styles.container} showsVerticalScrollIndicator={false} >
...Many components here
<ComponentWithScrollViewInside />
</ScrollView>
我从未找到根本原因,但您可以使用react-native-gesture-handler中的手势检测器作为解决方法:
export interface GestureTapHandlerProps {
onPress?: () => void;
children: React.ReactElement;
disabled?: boolean;
}
const GestureTapHandler = ({
onPress,
children,
disabled
}: GestureTapHandlerProps) => {
const tapHandler = Gesture.Tap()
.onEnd(() => {
console.log("Click", onPress, disabled);
if (onPress && !disabled) {
onPress();
}
})
.runOnJS(true);
return <GestureDetector gesture={tapHandler}>{children}</GestureDetector>;
};