【问题标题】:Swipe to delete on a tableView that is inside a pageViewController在 pageViewController 内的 tableView 上滑动以删除
【发布时间】:2016-08-09 17:20:53
【问题描述】:

我在pageViewController 内有一个tableView,当在单元格上滑动以调出删除单元格的选项时,手势仅在某些情况下才会被识别,例如您非常快速且积极地滑动。

我想这是因为不确定滑动手势是针对pageView 还是tableView。有没有办法专门确定滑动手势发生的位置,以实现删除按钮的流畅显示?

【问题讨论】:

  • 您可以添加一个编辑按钮。然后在编辑模式下,您可以禁用页面控制器滑动手势(通过设置委托 nil)。

标签: ios swift tableview uipageviewcontroller tableviewcell


【解决方案1】:

如果您在 UIPageViewController 内的第一个或最后一个 viewController 中有一个 tableView,可能会考虑先禁用 UIPageViewController 末尾的弹跳,然后实现this solution

如果您不知道如何禁用 UIPageViewController 的弹跳,请查看我的回答 here

【讨论】:

    【解决方案2】:

    理论:

    UIPageViewControllerUITableView 都使用UIScrollView 实现,其中UIPageViewController 嵌入UIScrollViewUITableViewUIScrollView 的子类

    UITableView 还使用了几个UIPanGestureRecognizers 来引入所有的魔法。其中之一是UISwipeActionPanGestureRecognizer,它处理滑动删除操作。

    这个问题是因为UIPageViewControllers UIPanGestureRecognizer在与UITableViews UISwipeActionPanGestureRecognizers的冲突中获胜。

    因此,如果UITableViews UISwipeActionPanGestureRecognizer 在起作用,我们必须知道如何告诉UIPageViewController 忽略手势。

    幸运的是UIGestureRecognizer已经提供了一些东西。

    UIGestureRecognizerrequire(toFail otherGestureRecognizer: UIGestureRecognizer) 在两个手势识别器之间创建一个关系,这将阻止手势的动作被调用,直到另一个手势识别器失败。

    所以我们所要做的就是在UITableViews UISwipeActionPanGestureRecognizer 被触发时使UIPageViewControllers 嵌入UIScrollviews panGestureRecognizer 失败。

    有两种方法可以实现。

    解决方案 1:向表格视图和 Mimic UISwipeActionPanGestureRecognizer 添加新的手势识别器。并使 UIPageViewController panGesture 要求使这个新的gestureRecognizer 失败

    解决方案 2(有点脏):与UITableViewUISwipeActionPanGestureRecognizer 进行字符串比较,并使UIPageViewController panGesture 要求使这个新的手势识别器失败

    代码:

    解决方案 1 一个有用的实用程序,可让 UIPageViewControllers 嵌入 UIScrollView

    extension UIPageViewController {
    
        var scrollView: UIScrollView? {
            return view.subviews.first { $0 is UIScrollView } as? UIScrollView
        }
    
    }
    

    将下面的代码添加到UIViewController 持有UITableView 并从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(有点脏) 一个有用的实用程序,可让 UIPageViewControllers 嵌入 UIScrollView

    extension UIPageViewController {
    
        var scrollView: UIScrollView? {
            return view.subviews.first { $0 is UIScrollView } as? UIScrollView
        }
    
    }
    

    将下面的代码添加到UIViewController 持有UITableView 并从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)
        }
    }
    

    【讨论】:

    • 好人,即使对于我在 containerview 内的 tableview 也能完美运行,它在另一个滚动视图内,即 UIPageViewcontroller 的子 ViewController
    • @Vasco 谢谢。并随时进行投票,以便此答案可以向上移动并让人们快速找到它。
    【解决方案3】:

    通过将UIScrollViewpanGestureRecognizerdelegate 重新分配给我的班级并在检测到从右到左的平移时忽略原始委托,我找到了一个可行的解决方案。我为此使用了方法调配。

    请查看我的示例项目:https://github.com/kambala-decapitator/SwipeToDeleteInsidePageVC

    【讨论】:

      【解决方案4】:

      您也可以在 tableView 本身上将 delaysContentTouches 设置为 false。此解决方案适用于我的集合视图的 UISlider 元素。

      参见下面的 Swift 4.0 代码:

      yourTableView.delaysContentTouches = false
      

      【讨论】:

        【解决方案5】:

        我遇到了同样的问题。我找到了一个行之有效的解决方案。

        把这个放在你的UIPageViewControllerviewDidLoad函数中。

        if let myView = view?.subviews.first as? UIScrollView {
            myView.canCancelContentTouches = false
        }
        

        PageViewControllers 有一个自动生成的处理手势的子视图。我们可以防止这些子视图取消内容触摸。 tableview 将能够捕获删除按钮的滑动,同时仍将不符合 tableview 手势要求的滑动解释为页面滑动。删除按钮将在您按住并滑动或“积极”滑动的情况下显示。

        【讨论】:

        • 我已将此添加到我的 UIPageViewController viewDidLoad 中,有时会发生滑动以删除 tableview 上的节目,但大多数时候它只是滑动到下一页......
        • 谢谢卡特。我试过你的解决方案。然而,pageViewController 仍然有时间超越子 tableView 的水平滑动动作。如何确保当用户在子 tableView 上滑动时,表格视图总是优先获得手势?
        猜你喜欢
        • 2021-05-08
        • 2012-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多