完整代码:
const LOADING_HEIGHT = 200;
function PanAndScrollView() {
const refreshY = useSharedValue(-LOADING_HEIGHT);
const scrollY = useSharedValue(0);
const {height: windowHeight} = useWindowDimensions();
const wrapperHeight = windowHeight + LOADING_HEIGHT;
const tapGesture = Gesture.Tap()
.onTouchesMove((_, manager) => {
if (LOADING_HEIGHT + refreshY.value === 0) {
manager.fail();
} else {
manager.activate();
}
})
.maxDuration(1000000);
const scrollGesture = Gesture.Native()
.requireExternalGestureToFail(tapGesture);
const panGesture = Gesture.Pan()
.onChange(e => {
if (scrollY.value === 0 || refreshY.value !== -LOADING_HEIGHT) {
refreshY.value = Math.max(-LOADING_HEIGHT, refreshY.value + e.changeY);
}
})
.onEnd(() => {
if (refreshY.value !== -LOADING_HEIGHT) {
refreshY.value = withSpring(-LOADING_HEIGHT, {
stiffness: 300,
overshootClamping: true,
});
}
})
.simultaneousWithExternalGesture(scrollGesture, tapGesture);
const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{translateY: refreshY.value}],
};
});
const scrollHandler = useAnimatedScrollHandler({
onScroll: e => {
scrollY.value = e.contentOffset.y;
},
});
return (
<GestureDetector gesture={panGesture}>
<Animated.View style={[{height: wrapperHeight}, animatedStyle]}>
<Text style={{height: LOADING_HEIGHT,}}>
loading...
</Text>
<GestureDetector
gesture={Gesture.Simultaneous(scrollGesture, tapGesture)}>
<Animated.ScrollView onScroll={scrollHandler} scrollEventThrottle={1}>
{Array(100).fill(1).map((_, index) => (<Text key={index}>{index}</Text>))}
</Animated.ScrollView>
</GestureDetector>
</Animated.View>
</GestureDetector>
);
}