ScrollView 平移手势和 panGestureRecognizer 冲突
Posted
技术标签:
【中文标题】ScrollView 平移手势和 panGestureRecognizer 冲突【英文标题】:Conflict between ScrollView pan gesture and panGestureRecognizer 【发布时间】:2018-01-28 21:48:12 【问题描述】:我在UIViewController
中有一个UIScrollView
,它通过segue 模态显示,另外一个UIPanGestureRecognizer
通过平移关闭视图控制器。此手势仅在
scrollView.contentOffset.y == 0
问题是,现在两个平移手势相互冲突,我无法再滚动视图。
为了解决这个问题,我尝试使用gestureRecognizer(_: shouldRecognizeSimultaneouslyWith:)
方法,返回是,并且我尝试将自定义平移手势添加到UIScrollView
平移手势识别器,如下所示:
scrollView.panGestureRecognizer.addTarget(self, action: #selector(handlePanGesture(_:)))
但这些并不能解决问题 如果您知道如何解决此问题,我将不胜感激。
已编辑
以下是我的平移手势关闭视图控制器的代码:
@IBAction func handlePanGesture(_ sender: UIPanGestureRecognizer)
let percentThreshold: CGFloat = 0.3
if scrollView.contentOffset.y == 0
let translation = sender.translation(in: view)
let verticalMovement = translation.y / view.bounds.height
let downwardMovement = fmaxf(Float(verticalMovement), 0.0)
let downwardMovementPercent = fminf(downwardMovement, 1.0)
let progress = CGFloat(downwardMovementPercent)
guard let interactor = interactor else return
switch sender.state
case .began:
interactor.hasStarted = true
dismiss(animated: true, completion: nil)
case .changed:
interactor.shouldFinish = progress > percentThreshold
interactor.update(progress)
case .cancelled:
interactor.hasStarted = false
interactor.cancel()
case .ended:
interactor.hasStarted = false
interactor.shouldFinish ? interactor.finish() : interactor.cancel()
default:
break
EDITED_2
这是Interactor
的代码:
class Interactor: UIPercentDrivenInteractiveTransition
var hasStarted = false
var shouldFinish = false
附:我知道有很多类似的问题,但它们对我不起作用。
【问题讨论】:
如果您使用UINavigationController
,它应该会自动滑动返回,除非您明确移除手势识别器。 developer.apple.com/documentation/uikit/uinavigationcontroller/…
@Samah,问题与返回无关。我的视图控制器以模态方式显示,因此无法通过滑动返回(即使它在导航控制器中)
我不明白你的用例。您希望用户向哪个方向滑动以关闭对话框?
@Samah,我的视图控制器以模态方式出现,因此它从屏幕底部出现。我通过从上到下平移来消除它。问题是,我的滚动视图也可以垂直滚动,所以两个平移手势之间存在冲突,我需要解决它
你有没有考虑过只对两个动作都使用滚动视图的识别器?
【参考方案1】:
要在 UIPanGestureRecognizer
位于 ScrollView 上时允许滚动,您需要创建一个在 gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
上返回 true 的 UIGestureRecognizerDelegate
如果您不这样做,则 ScrollView 上将无法滚动。
这样做是这样的:
let scrollViewPanGesture = UIPanGestureRecognizer(target: self, action: #selector(onPan(_:)))
scrollViewPanGesture.delegate = self
scrollView.addGestureRecognizer(scrollViewPanGesture)
extension ViewController: UIGestureRecognizerDelegate
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
return true
【讨论】:
我试过了,但没有成功。我通过使用 scrollView 的contentOffset.y
值来关闭视图解决了这个问题。【参考方案2】:
我不确定,但您可以尝试将ViewController
添加为滑动的UIPanGestureRecognizer
代表以关闭平移手势并实现gestureRecognizerShouldBegin(_:)
;
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
return scrollView.contentOffset.y == 0
所以只有当内容偏移量为零时才会开始关闭手势。
【讨论】:
感谢您的回答。它有效,但仅在滚动之前(我既可以关闭 VC 也可以滚动)。但是经过一些滚动(并返回到scrollView.contentOffset.y == 0
的位置)后,我的平移手势停止工作。也许您知道如何处理?
你能分享一些其他的代码吗?我不知道我是否完全理解你的问题
我不知道你到底需要什么,所以我添加了平移手势的代码。
我还注意到,当我将滚动视图滚动到顶部时,内容偏移量并不完全是 0.0 。但即使我以编程方式将其设置为 0.0 并触发方法内的断点,我的自定义平移手势也会停止工作(仅滚动视图的平移有效)
什么是交互器?【参考方案3】:
在滚动视图下添加一个子视图并将平移手势添加到它而不是将其添加到 self.view 肯定会与滚动视图的冲突
【讨论】:
我已经添加了,但现在我的自定义平移手势动作没有被调用。我猜原因是我的滚动视图覆盖了它下面的视图,所以它没有得到调用 覆盖滚动视图的hitTest:withEvent: ,如果触摸点在子视图的框架内则返回子视图【参考方案4】:你在实施时做对了gestureRecognizer(_: shouldRecognizeSimultaneouslyWith:)
但是您必须先将手势委托设置为当前的 View Controller:
let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(handlePanGesture(_:)))
panGesture.delegate = self // <--THIS
scrollView.addGestureRecognizer(panGesture)
【讨论】:
我已经做到了,但不幸的是没有成功。我的自定义平移“吃掉”手势,因此不会调用滚动视图的手势。所以,问题不在于我不能调用我的平移手势,而是我不能调用滚动视图的平移手势来进行滚动以上是关于ScrollView 平移手势和 panGestureRecognizer 冲突的主要内容,如果未能解决你的问题,请参考以下文章
带有其他手势的 ScrollView 中的 2 个手指平移 - iOS SDK