Swift中仅跟踪连续手势首次触摸的手势识别器实现问题
解决单指拖动调整视图大小的多手指干扰问题
这个问题我之前也碰到过!默认的手势识别器会对额外触摸做出响应,导致单指拖动的逻辑乱掉,下面分平台给你具体的解决思路和代码:
iOS 平台(Swift)
核心思路是严格限制手势只响应单指触摸,并在手势过程中校验触摸数量,避免额外手指干扰:
- 初始化手势时设置触摸数量限制:
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:))) // 只允许单指触发和跟踪 panGesture.minimumNumberOfTouches = 1 panGesture.maximumNumberOfTouches = 1 yourTargetView.addGestureRecognizer(panGesture)
- 在手势处理方法中额外校验,确保只处理单指操作:
// 记录初始状态的变量 private var initialViewSize: CGSize = .zero private var initialTouchPosition: CGPoint = .zero @objc private func handlePanGesture(_ gesture: UIPanGestureRecognizer) { // 如果当前触摸数量不是1,直接取消手势 guard gesture.numberOfTouches == 1 else { gesture.state = .cancelled return } switch gesture.state { case .began: // 记录视图初始大小和触摸初始位置 initialViewSize = yourTargetView.bounds.size initialTouchPosition = gesture.location(in: yourTargetView.superview) case .changed: // 计算触摸位移,调整视图大小 let currentTouchPos = gesture.location(in: yourTargetView.superview) let deltaX = currentTouchPos.x - initialTouchPosition.x let deltaY = currentTouchPos.y - initialTouchPosition.y yourTargetView.bounds.size = CGSize( width: initialViewSize.width + deltaX, height: initialViewSize.height + deltaY ) case .ended, .cancelled: // 收尾逻辑(如果需要) break default: break } }
这样设置后,无论是同时多手指触摸,还是拖动过程中加入额外手指,手势都会直接取消或忽略,完全只响应第一个触摸的拖动动作。
Android 平台(Kotlin)
Android这边需要手动跟踪第一个触摸的Pointer ID,后续只处理这个ID的触摸事件,忽略其他手指:
private var activeTouchPointerId: Int = -1 private var initialViewWidth: Int = 0 private var initialViewHeight: Int = 0 private var initialTouchX: Float = 0f private var initialTouchY: Float = 0f yourTargetView.setOnTouchListener { v, event -> when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { // 记录第一个触摸的ID和初始状态 activeTouchPointerId = event.getPointerId(0) initialViewWidth = v.layoutParams.width initialViewHeight = v.layoutParams.height initialTouchX = event.x initialTouchY = event.y true } MotionEvent.ACTION_MOVE -> { // 找到当前活跃触摸的索引 val pointerIndex = event.findPointerIndex(activeTouchPointerId) if (pointerIndex == -1) { // 第一个触摸已经离开,终止操作 activeTouchPointerId = -1 return@setOnTouchListener false } // 计算位移并调整视图大小 val currentX = event.getX(pointerIndex) val currentY = event.getY(pointerIndex) val deltaX = currentX - initialTouchX val deltaY = currentY - initialTouchY v.layoutParams.width = (initialViewWidth + deltaX).toInt() v.layoutParams.height = (initialViewHeight + deltaY).toInt() v.requestLayout() true } MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { // 重置活跃触摸ID activeTouchPointerId = -1 true } MotionEvent.ACTION_POINTER_DOWN -> { // 有新手指加入,直接终止当前手势 activeTouchPointerId = -1 true } else -> false } }
这个逻辑会在检测到额外手指触摸时,直接放弃当前的拖动操作,确保只有第一个手指的动作会触发视图大小调整。
内容的提问来源于stack exchange,提问作者kmell96
相关产品推荐
相关产品推荐

