Flutter中实现多手势识别:类WhatsApp录音按钮开发问题
实现类似WhatsApp的录音按钮滑动手势检测
核心逻辑很清晰:长按触发录音后,持续监听触摸点的坐标变化,通过计算当前坐标与初始长按坐标的偏移量,判断滑动方向(上滑/左滑),达到设定阈值后触发对应操作。
Android 实现(Kotlin)
通过OnLongClickListener启动录音,同时配合OnTouchListener监听后续触摸移动事件:
private var isLongPressActive = false private var initialTouchX = 0f private var initialTouchY = 0f // 滑动阈值(dp转px,适配不同分辨率) private val swipeThreshold = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20f, resources.displayMetrics).toInt() recordButton.setOnLongClickListener { // 启动录音 startRecording() isLongPressActive = true true } recordButton.setOnTouchListener { _, event -> when (event.action) { MotionEvent.ACTION_DOWN -> { // 记录初始触摸坐标 initialTouchX = event.x initialTouchY = event.y false } MotionEvent.ACTION_MOVE -> { if (isLongPressActive) { val deltaX = event.x - initialTouchX val deltaY = event.y - initialTouchY // 判断左滑:X轴负向偏移,且绝对值超过阈值,优先判断单一方向 if (deltaX < -swipeThreshold && Math.abs(deltaX) > Math.abs(deltaY)) { // 执行左滑操作(比如取消录音) onSwipeLeft() isLongPressActive = false } // 判断上滑:Y轴负向偏移,且绝对值超过阈值 else if (deltaY < -swipeThreshold && Math.abs(deltaY) > Math.abs(deltaX)) { // 执行上滑操作(比如锁定录音) onSwipeUp() } } true } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { if (isLongPressActive) { // 结束录音 stopRecording() isLongPressActive = false } true } else -> false } }
关键注意点:
- 用
isLongPressActive标记长按状态,过滤非长按的误触移动事件 - 比较X/Y偏移的绝对值,确保是单一方向滑动,避免斜滑误判
- 左滑后可直接终止长按状态,上滑通常需保持录音(如WhatsApp的锁定录音逻辑)
iOS 实现(Swift)
基于UILongPressGestureRecognizer处理长按及后续滑动逻辑:
var isLongPressActive = false var initialTouchPoint: CGPoint = .zero let swipeThreshold: CGFloat = 20 // 滑动阈值(可转dp适配多分辨率) let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) recordButton.addGestureRecognizer(longPressGesture) @objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) { switch gesture.state { case .began: // 启动录音 startRecording() isLongPressActive = true initialTouchPoint = gesture.location(in: recordButton) case .changed: guard isLongPressActive else { return } let currentPoint = gesture.location(in: recordButton) let deltaX = currentPoint.x - initialTouchPoint.x let deltaY = currentPoint.y - initialTouchPoint.y // 判断左滑 if deltaX < -swipeThreshold && abs(deltaX) > abs(deltaY) { onSwipeLeft() isLongPressActive = false gesture.state = .ended } // 判断上滑 else if deltaY < -swipeThreshold && abs(deltaY) > abs(deltaX) { onSwipeUp() } case .ended, .cancelled, .failed: if isLongPressActive { stopRecording() isLongPressActive = false } default: break } }
关键注意点:
- 在
changed状态实时计算坐标偏移,判断滑动方向 - 左滑后手动将手势状态设为
.ended,避免后续事件干扰 - 可根据需求添加滑动过程中的UI反馈(如按钮跟随滑动位移)
内容的提问来源于stack exchange,提问作者khaled mohamed
相关产品推荐
相关产品推荐

