我在一个pageViewController
中放置了一个tableView
,当滑动单元格以显示删除选项时,手势只在某些情况下被识别,比如你非常快速和激进地滑动。
我想这是因为它不确定滑动手势是针对pageView
还是tableView
。是否有一种特定的方式来确定滑动手势发生的位置,以启用漂亮而平滑地显示删除按钮的效果?
我在一个pageViewController
中放置了一个tableView
,当滑动单元格以显示删除选项时,手势只在某些情况下被识别,比如你非常快速和激进地滑动。
我想这是因为它不确定滑动手势是针对pageView
还是tableView
。是否有一种特定的方式来确定滑动手势发生的位置,以启用漂亮而平滑地显示删除按钮的效果?
理论:
UIPageViewController
和UITableView
都使用UIScrollView
实现,其中UIPageViewController
嵌入了UIScrollView
,而UITableView
是UIScrollView
的子类。
UITableView
还使用了一些UIPanGestureRecognizer
来实现一些功能。其中之一是UISwipeActionPanGestureRecognizer
,用于处理滑动删除操作。
这个问题是由于UIPageViewController
的UIPanGestureRecognizer
在与UITableView
的UISwipeActionPanGestureRecognizer
冲突时获胜所导致的。
因此,我们必须想办法告诉UIPageViewController
如果UITableView
的UISwipeActionPanGestureRecognizer
正在执行,则应忽略手势。
幸运的是,UIGestureRecognizer
已经提供了一些方法。
UIGestureRecognizer
的require(toFail otherGestureRecognizer:UIGestureRecognizer)
创建了两个手势识别器之间的关系,以防止手势动作被调用,直到另一个手势识别器失败为止。
所以我们需要做的就是在UIPageViewControllers
嵌入UIScrollview
时,当触发UITableView
的UISwipeActionPanGestureRecognizer
时,将其panGestureRecognizer
设置为失败。
有两种方法可以实现这个目标。
解决方案1:向表视图添加一个新的手势识别器,并模仿UISwipeActionPanGestureRecognizer
。并使UIPageViewController panGesture需要失败此新的gestureRecognizer
解决方案2(有点不太好):对UITableView
的UISwipeActionPanGestureRecognizer
进行字符串比较,并使UIPageViewController
panGesture需要失败此新的gestureRecognizer
代码:
解决方案1
一个有用的工具来获取UIPageViewController
嵌入的UIScrollView
extension UIPageViewController {
var scrollView: UIScrollView? {
return view.subviews.first { $0 is UIScrollView } as? UIScrollView
}
}
UITableView
的UIViewController
中,并从viewDidLoad()
调用它。func handleSwipeDelete() {
if let pageController = parent?.parent as? UIPageViewController {
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: nil)
gestureRecognizer.delaysTouchesBegan = true
gestureRecognizer.cancelsTouchesInView = false
gestureRecognizer.delegate = self
tableView.addGestureRecognizer(gestureRecognizer)
pageController.scrollView?.canCancelContentTouches = false
pageController.scrollView?.panGestureRecognizer.require(toFail: gestureRecognizer)
}
}
最后是委托方法
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let panGesture = gestureRecognizer as? UIPanGestureRecognizer else {
return false
}
let translation = panGesture.translation(in: tableView)
// In my case I have only trailing actions, so I used below condition.
return translation.x < 0
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return otherGestureRecognizer.view == tableView
}
解决方案2(有点不太干净)
一个有用的工具,可以获取嵌入了UIScrollView
的UIPageViewController
。extension UIPageViewController {
var scrollView: UIScrollView? {
return view.subviews.first { $0 is UIScrollView } as? UIScrollView
}
}
UITableView
的UIViewController
中,并从viewDidLoad()
调用它。func handleSwipeDelete() {
guard let pageController = parent as? UIPageViewController else {
return
}
pageController.scrollView?.canCancelContentTouches = false
tableView.gestureRecognizers?.forEach { recognizer in
let name = String(describing: type(of: recognizer))
guard name == "_UISwipeActionPanGestureRecognizer" else {
return
}
pageController.scrollView?
.panGestureRecognizer
.require(toFail: recognizer)
}
}
我有同样的问题。我找到了一个有效的解决方案。
将以下内容放入您的UIPageViewController
的viewDidLoad
函数中。
if let myView = view?.subviews.first as? UIScrollView {
myView.canCancelContentTouches = false
}
PageViewControllers有一个自动生成的子视图来处理手势。我们可以防止这些子视图取消内容触摸。表格视图将能够捕获删除按钮的滑动,同时解释未能满足表格视图手势要求的滑动为页面滑动。在你按住并滑动或"积极地"滑动时,删除按钮将显示。
我已经找到了一个可行的解决方案,通过将UIScrollView
的panGestureRecognizer
的delegate
重新分配给我的类,并在检测到从右到左的手势时忽略原始代理。 我使用方法交换实现了这一点。
请检查我的示例项目:https://github.com/kambala-decapitator/SwipeToDeleteInsidePageVC
你也可以在tableView本身上将delaysContentTouches设置为false。这个解决方案对我的集合视图中的UISlider元素有效。
请参见下面的Swift 4.0代码:
yourTableView.delaysContentTouches = false