首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在UIScrollView中添加垂直双指滑动手势

在UIScrollView中添加垂直双指滑动手势
EN

Stack Overflow用户
提问于 2018-10-20 16:56:31
回答 1查看 1.4K关注 0票数 4

根据如何为所有屏幕添加垂直滑动手势到iPhone应用程序的说法,我给window添加了一个双指向下滑动的手势,这在整个应用程序的普通页面上运行得很好。但是它在有UIScrollView的页面上失败了(比如UITableViewController)。当我用两根手指在上滑动时,它只是像往常一样滚动。如果我从UINavigationBar上滑过UIScrollView,它又能正常工作了。

理想的结果是,我可以正常滚动一个手指的表视图,并调用一些方法,用两个手指滑动页面,而不滚动表视图。这是用于TweetBot切换暗模式,工作完美。

根据苹果公司的文件:使用Responders和Responder链处理事件,我想我理解应答器链是如何工作的,所以我想让UIScrollView忽略这两个手指的滑动手势,这样它就可以把这个事件传递给UIWindow。但我想不出如何:

我试着从苹果的UIGestureRecognizerDelegate文档中实现func gestureRecognizer(_:, shouldRequireFailureOf otherGestureRecognizer:),或者通过继承UITableView来覆盖gestureRecognizerShouldBegin(_),但都没有成功。

欢迎任何解决方案或建议。

更新-最终解决方案

我简化了joern的解决方案,下面是。

AppDelegate

代码语言:javascript
复制
// It's not necessary to keep a reference to gesture unless you want to do something further.
lazy var gesture: UIPanGestureRecognizer = {
    let gesture = UIPanGestureRecognizer(target: self, action: #selector(twoFingerDidSwipe(recognizer:)))
    gesture.minimumNumberOfTouches = 2
    gesture.maximumNumberOfTouches = 2
    return gesture
}()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    gesture.delegate = AppDelegate
    window.addGestureRecognizer(gesture)
    return true
}

@objc func twoFingerDidSwipe(recognizer: UIPanGestureRecognizer) {
    let swipeThreshold: CGFloat = 50

    if recognizer.state == .changed { // 1
      switch recognizer.translation(in: window).y { // 2
      case ...(-swipeThreshold):
        print("Swipe Up")
        recognizer.state = .cancelled // 3
      case swipeThreshold...:
        print("Swipe Down")
        recognizer.state = .cancelled
      default:
        break
      }
    }
}

代码语言:javascript
复制
extension AppDelegate: UIGestureRecognizerDelegate {
  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
  }
}

关于与joern解决方案不同之处的一些解释:

  1. 唯一关心的是recognizer.state == .change
  2. recognizer.translation(in:)的参数应该是window,这样我就不能对特定的VC做任何事情。
  3. 在此识别器触发某些方法后,应取消该方法,以防止其继续触发。

没有必要对任何特定的VC做任何事情。

这样,双指滑动手势在普通VC和滚动VC上都能很好地工作.

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-24 14:28:20

UISwipeGestureRecognizer添加到窗口时,保留对它的引用,以便以后可以通过AppDelegate访问它。

代码语言:javascript
复制
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var twoFingerSwipeDownRecognizer: UISwipeGestureRecognizer?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let twoFingerSwipeDownRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(didRecognizeTwoFingerSwipeDown))
        twoFingerSwipeDownRecognizer.numberOfTouchesRequired = 2
        twoFingerSwipeDownRecognizer.direction = .down
        window?.addGestureRecognizer(twoFingerSwipeDownRecognizer)
        self.twoFingerSwipeDownRecognizer = twoFingerSwipeDownRecognizer

        return true
    }

    @objc func didRecognizeTwoFingerSwipeDown(recognizer: UISwipeGestureRecognizer) {
        print("SWIPE DOWN")
    }
}

然后,在包含UITableView (或UIScrollView)的UITableView中,您必须在UITableView的pan手势识别器上调用require(toFail:)

代码语言:javascript
复制
func enableTwoFingerSlideDown() {
    guard
        let appDelegate = UIApplication.shared.delegate as? AppDelegate,
        let twoFingerGestureRecognizer = appDelegate.twoFingerSwipeDownRecognizer
        else {
            return
        }
    tableView.panGestureRecognizer.require(toFail: twoFingerGestureRecognizer)
}

现在,两根手指向下的手势在UITableView上起作用。

更新

因为滑动是一个离散的手势,上面的解决方案可能不是完美的解决方案。当您用一个手指慢慢向下滚动时,您会注意到UITableView不会立即向下滚动。由于UITableView's UIPanGestureDelagate必须等待(两个手指) SwipeDelegate失败,所以延迟时间很短。这需要一些时间。

更好的解决方案可能是使用UIPanGestureRecognizer识别两个手指盘,然后在用户使用两个手指进行摇摄时禁用UITableView上的滚动。

这是可以做到的:

In your AppDelegate:

代码语言:javascript
复制
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var twoFingerPanRecognizer: UIPanGestureRecognizer?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        let twoFingerSwipeDownRecognizer = UIPanGestureRecognizer(target: self, action: #selector(didRecognizeTwoFingerPan))
        twoFingerSwipeDownRecognizer.minimumNumberOfTouches = 2
        twoFingerSwipeDownRecognizer.maximumNumberOfTouches = 2
        twoFingerPanRecognizer?.delegate = self
        window?.addGestureRecognizer(twoFingerSwipeDownRecognizer)
        self.twoFingerPanRecognizer = twoFingerSwipeDownRecognizer

        return true
    }

    @objc func didRecognizeTwoFingerPan(recognizer: UIPanGestureRecognizer) {
        let tableView = recognizer.view as? UITableView
        switch recognizer.state {
        case .began:
            tableView?.isScrollEnabled = false
        case .changed:
            let swipeThreshold: CGFloat = 50
            switch recognizer.translation(in: nil).y {
            case ...(-swipeThreshold):
                print("Swipe UP")
                recognizer.isEnabled = false
            case swipeThreshold...:
                print("Swipe DOWN")
                recognizer.isEnabled = false
            default:
                break
            }
        case .cancelled, .ended, .failed, .possible:
            tableView?.isScrollEnabled = true
            recognizer.isEnabled = true
        }
    }
}

extension AppDelegate: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

In your ViewController:

代码语言:javascript
复制
func enableTwoFingerSlideDown() {
        guard
            let appDelegate = UIApplication.shared.delegate as? AppDelegate,
            let twoFingerGestureRecognizer = appDelegate.twoFingerPanRecognizer
            else {
                return
            }
        tableView.addGestureRecognizer(twoFingerGestureRecognizer)
    }

您必须从UIPanGestureRecognizer中获取AppDelegate并将其添加到UITableView中。否则这就行不通了。请记住,在此UIWindow被取消之前,请将其添加回UIViewController

使用此解决方案,UITableView的正常滚动行为保持不变。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52908002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档