UICollectionView子视图拖拽移动时避免父视图滚动问题求助
我明白你的痛点——拖拽子视图时UICollectionView总是先偷偷滚一下,哪怕你在手势开始时关闭滚动也有延迟,之前的手势拦截代码还没起作用对吧?咱们来一步步解决这个问题:
1. 先排查坐标转换的坑(你的原始代码可能栽在这里)
你之前判断item.frame.contains(touch.location(in: self.collectionView!)),这里的坐标系统根本不匹配:item.frame是相对于它直接父视图的坐标,而touch.location(in: collectionView)是相对于UICollectionView的全局坐标,两者不在一个维度,导致判断失效,collectionView的pan手势还是会接收到触摸事件。
修改判断逻辑,把触摸点转换到item的父视图坐标系里,或者把item的frame转换到collectionView坐标系:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { guard let collectionView = collectionView else { return true } // 把触摸点转换到item的父视图坐标系,再判断是否在item范围内 let touchLocationInItemSuperview = touch.location(in: item.superview) if gestureRecognizer == collectionView.panGestureRecognizer && item.frame.contains(touchLocationInItemSuperview) { return false } return true }
2. 给自定义拖拽手势设置更高优先级
如果坐标问题解决了还是失效,那大概率是手势识别顺序的锅——UICollectionView的pan手势抢在你的自定义拖拽手势之前触发了。你可以通过手势代理让自定义手势先“拿到”事件:
假设你的自定义拖拽手势叫dragGesture,给它设置delegate后实现下面的方法:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool { // 要求collectionView的pan手势,必须等我们的拖拽手势识别失败后才能触发 return otherGestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer.view == collectionView }
3. 配合滚动禁用的即时操作兜底
如果还是有极其轻微的滚动残留,在自定义拖拽手势的began状态里立即禁用滚动,结束时恢复,结合上面的手势优先级设置,就能彻底解决:
@objc func handleDragGesture(_ gesture: UIPanGestureRecognizer) { switch gesture.state { case .began: collectionView?.isScrollEnabled = false case .ended, .cancelled, .failed: collectionView?.isScrollEnabled = true case .changed: // 这里写你的拖拽移动逻辑 let translation = gesture.translation(in: view) item.center = CGPoint(x: item.center.x + translation.x, y: item.center.y + translation.y) gesture.setTranslation(.zero, in: view) default: break } }
内容的提问来源于stack exchange,提问作者HelloimDarius
相关产品推荐
相关产品推荐

