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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 07:18:00