React Native实现类谷歌地图可拖拽底部抽屉Y轴无法拖动问题求助
修复方案
核心问题点
- PanResponder回调参数错误:所有PanResponder事件回调的第一个参数为原生事件对象,第二个才是手势状态对象
gestureState,你的代码直接将第一个参数当作手势状态使用,无法获取正确的拖拽位移,这是拖拽失效的核心原因。 - 手势触发判断逻辑错误:
onMoveShouldSetPanResponder中需要判断的是手势状态的dy属性(Y轴移动偏移量)的绝对值,而非直接判断手势状态对象本身。 - 抽屉状态取值错误:
state是Animated.Value类型,不能直接传入getNextState作为当前状态,需要取它的原始值state._value使用。 - 位移计算逻辑错误:
movementValue函数需要从手势状态中取moveY属性计算,不能直接用手势状态对象计算。
修复后代码
组件代码
import React, { useRef } from 'react' import { StyleSheet, View, Animated, PanResponder } from 'react-native' import Colors from '../global/Colors' import Constants from '../global/Constants' import { BottomDrawerType } from '../global/Enumerations' const BottomDrawerView = () => { const y = useRef(new Animated.Value(BottomDrawerType.Closed)).current const state = useRef(new Animated.Value(BottomDrawerType.Closed)).current const margin = 0.05 * Constants.Size.screenHeight /** * Functionalities */ const movementValue = (moveY) => Constants.Size.screenHeight - moveY const animateMove = (y, toValue, callback) => { Animated.spring(y, { toValue: -toValue, tension: 20, useNativeDriver: true, }).start((finished) => { finished && callback && callback() }) } const getNextState = ( currentState, val, margin, ) => { switch (currentState) { case BottomDrawerType.Peek: return val >= currentState + margin ? BottomDrawerType.Open : val <= BottomDrawerType.Peek - margin ? BottomDrawerType.Closed : BottomDrawerType.Peek; case BottomDrawerType.Open: return val >= currentState ? BottomDrawerType.Open : val <= BottomDrawerType.Peek ? BottomDrawerType.Closed : BottomDrawerType.Peek; case BottomDrawerType.Closed: return val >= currentState + margin ? val <= BottomDrawerType.Peek + margin ? BottomDrawerType.Peek : BottomDrawerType.Open : BottomDrawerType.Closed; default: return currentState; } } // 修复:增加第一个event参数,取gestureState.moveY const onPanResponderMove = (_, gestureState) => { const val = movementValue(gestureState.moveY) animateMove(y, val) } // 修复:增加第一个event参数,取gestureState.moveY,传入当前state原始值 const onPanResponderRelease = (_, gestureState) => { const valueToMove = movementValue(gestureState.moveY) const nextState = getNextState(state._value, valueToMove, margin) state.setValue(nextState) animateMove(y, nextState) } // 修复:判断gestureState.dy的绝对值 const onMoveShouldSetPanResponder = (_, gestureState) => Math.abs(gestureState.dy) >= 10 const panResponder = useRef( PanResponder.create({ onMoveShouldSetPanResponder, onStartShouldSetPanResponderCapture: onMoveShouldSetPanResponder, onPanResponderMove, onPanResponderRelease, }), ).current /** * UI */ return ( <Animated.View style={[styles.contentView, { transform: [{ translateY: y }] }]} {...panResponder.panHandlers}> <View style={styles.horizontalLine} /> {/* 抽屉内容区域可自行扩展 */} </Animated.View> ) } const styles = StyleSheet.create({ contentView: { position: 'absolute', bottom: -Constants.Size.screenHeight + 70, width: Constants.Size.screenWidth, height: Constants.Size.screenHeight, backgroundColor: Colors.turqoise, borderRadius: Constants.Layout.borderRadius, }, horizontalLine: { marginTop: 25, marginBottom: 15, marginHorizontal: 0, height: 2, width: '100%', backgroundColor: Colors.main } }) export default BottomDrawerView
BottomDrawerType定义(确认无问题)
const BottomDrawerType = { Open: Constants.Size.screenHeight - 230, Peek: 230, Closed: 0 }
内容的提问来源于stack exchange,提问作者poPaTheGuru
相关产品推荐
相关产品推荐

