感谢作者ruwatana, 我只是翻译并学习该文. 如果有错误欢迎指正.
前言
如果想控制自定义的UIGestureRecognizer的识别,或者同时控制其他手势的失败的情况,我想应该会很多.
这个时候用UIGestureRecognizerDelegate会方便很多.
虽然提供了各种各样的方法,但是日语的资料不是很多(原文是日语,本文只是翻译一下),总结了一下哪种情况下会用到哪种方法.
UIGestureRecognizerDelegate
UIGestureRecognizerDelegate是一个为了微调手势的识别的protocal.
它提供了6个协议方法,都是optional的.
public protocol UIGestureRecognizerDelegate : NSObjectProtocol {
// 控制Gesture的开始
@available(iOS 3.2, *)
optional public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
// 控制Gesture是否可以同时识别
@available(iOS 3.2, *)
optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
// 控制自身的Gesture和其他Gesture的失败
@available(iOS 7.0, *)
optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool
@available(iOS 7.0, *)
optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool
// 控制Gesture是否接受touch
@available(iOS 3.2, *)
optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
// 控制Gesture是否接受press
@available(iOS 9.0, *)
optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive press: UIPress) -> Bool
}
使用方法
使用方法很简单.想要实现协议的对象设置为UIGestureRecognizer的delegate就可以了.
class ViewController: UIViewController {
var gesture: UIGestureRecognizer?
override func viewDidLoad() {
super.viewDidLoad()
// gesture的初始化
// 设置delegate
gesture?.delegate = self
}
}
extension ViewController: UIGestureRecognizerDelegate {
// 在这里实现delegate方法
}
delegate方法介绍
在这里将UIGestureRecognizerDelegate分为三类控制方法介绍
- 识别控制系方法
- 同时识别控制系方法
- 失败控制系方法
识别控制系方法
-
gestureRecognizerShouldBegin 方法
- 想要控制识别开始与否的时候, 实现该方法. 可能会是UIGestureRecognizerDelegate中所有方法里用途最多的.
- UIGestureRecognizer的state会根据.possible, .began, .changed, .ended, .cancelled, .failed这种具体的识别状态发生变化.
- gestureRecognizerShouldBegin这个方法控制上述状态中的.possible 是变成.began 还是.failed
- 如果不实现该方法 default返回值是true.
- 比如, 想实现控制特定的gesture的场合, 使用如下:
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer === tap0gesture { // 判断该gesture是否是指定的gesture 从而进行控制
// hogehoge
return false // tap0click不会被调用
}
return true // tap0click会被调用
}
- shouldReceive touch方法
- 会先于ShouldBegin之前被调用, 是控制是否接受touch的.如果返回true,则下一步ShouldBegin()方法会被调用.false的场合ShouldBegin()不会被调用
- 是控制当前view接不接受touch的场合使用的.
比如:
orangeView的tag是10010
self.view的tag是10012
代码:
class ViewController: UIViewController {
@objc func tap0click(tap: UITapGestureRecognizer) {
print("tap 10010 click")
}
@objc func tap2click(tap: UITapGestureRecognizer) {
print("tap 10012 click")
}
override func viewDidLoad() {
super.viewDidLoad()
// 第一个view
let view0 = CustomView0(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
self.view.addSubview(view0)
view0.backgroundColor = UIColor.orange
view0.tag = 10010
let tap0 = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap0click(tap:)))
view0.addGestureRecognizer(tap0)
tap0.delegate = self
let tap2 = UITapGestureRecognizer(target: self, action: #selector(ViewController.tap2click(tap:)))
self.view.addGestureRecognizer(tap2)
self.view.tag = 10012
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController : UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
print("gesture recognizer should receive touch in view : \(String(describing: gestureRecognizer.view?.tag))")
print("gesture recognizer touch in view \(String(describing: touch.view?.tag))")
return false
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
print("gesture recognizer should begin in view : \(String(describing: gestureRecognizer.view?.tag))")
return true
}
}
返回的结果为:
Screen Shot 2017-10-28 at 10.16.14 PM.png如果shouldReceive回调方法返回值为true
返回的结果为:
Screen Shot 2017-10-28 at 10.17.06 PM.png- shouldReceive press方法和touch类似.
- 只支持iOS9以上
同时识别控制系方法
- shouldRecognizeSimultaneouslyWith方法
- 这个方法是同时识别复数个gesture的时候被使用.
- 比如viewController的view上有一个scrollView的这种情况, 按理来说,会识别最上面那一层的view, 所以scrollView里内置的gesture会被识别, 而被加到viewController.view的自定义gesture不会被识别.
- 在上面一种情况下,如果利用shouldRecognizeSimultaneouslyWith这个回调方法, 如果设置同时识别两种gesture, 加载viewController.view上的自定义的gesture也会被识别.
- 使用方法很简单, 想同时识别的两种gesture, 则返回true, 反之返回false.
- defalult返回值为false
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer === self.gesture { // 判断特定手势
// hogehoge
}
if otherGestureRecognizer is UIPanGestureRecognizer { // 判断其他另一个手势
// hogehoge
}
if otherGestureRecognizer.view is UIScrollView { // 判断其他手势是加在UIScrollView上的情况
// hogehoge
}
return false
}
还是上面的orageView那个例子.如果设置同时识别回调方法的返回值为false:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return false
}
返回结果:
Screen Shot 2017-10-28 at 8.54.07 PM.png如果设置返回值为true:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
返回结果:
Screen Shot 2017-10-28 at 8.54.39 PM.png失败控制系方法
这个方法是两个gesture都识别的情况下, 控制gestureRecognizer的失败, 或者另一个otherGestureRecognizer的失败的时候使用.
-
shouldRequireFailureOf方法:
- 这个方法是控制当前gesture本身(设置delegate的gesture)的失败的方法. 此处很容易与另一个失败回调shouldBeRequiredToFailBy混淆, 需要注意.
- 返回true的时候, 控制当前gesture失败.
- 在没有其他gesture的情况下,即使返回true也不会失败.
- default值是false
-
shouldBeRequiredToFailBy方法:
- 与上面的方法对应, 此方法是控制其他方法的成功与失败.
- 请注意:如果当前gesture失败的情况下, 也就是上面的shouldRequireFailureOf方法返回的是true(原文里写的是false, 感觉写错了), 根本不会走到shouldBeRequiredToFailBy方法, 所以这种情况无论返回true或者false都不会生效.
shouldRequireFailureOf方法 返回TRUE时 参数gestureRecognizer会失败.
shouldBeRequiredToFailBy方法 返回TRUE时 参数otherGestureRecognizer会失败.
Tips: UIKit中的系统类里使用的gesture是不能设置delegate的.
不是自定义的gesture, 而是UIKit中封装好的手势(比如UITableView或者UIScrollView的panGestureRecognizer 等等..)
如果给UITableView(UIScrollView)设置tableview.panGestureRecognizer.delegate = self;, 会崩溃. 提示信息如下:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.'
网友评论