• UIGestureRecognizer
  • UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能等到具体手势
  • UITapGestureRecognizer 敲击
  • UIPinchGestureRecognizer 捏合,用于缩放
  • UIPanGestureRecognizer 拖拽
  • UISwipeGestureRecognizer 轻扫
  • UIRotationGestureRecognizer 旋转
  • UILongPressGestureRecognizer 长按
  • UIScreenEdgePanGestureRecognizer 屏幕边缘平移 手势
  • 常用属性和方法
public init(target: Any?, action: Selector?)      
// 为手势添加动作 (一个手势可以拥有多个动作,当手势相应时会一同触发其所有的事件)
    open func addTarget(_ target: Any, action: Selector)    
// 移除动作
    open func removeTarget(_ target: Any?, action: Selector?)
// 设置手势可用
    open var isEnabled: Bool
// 获取手势所作用的 view 
    open var view: UIView? { get }
// 获取手势在指定 view 的坐标
    open func location(in view: UIView?) -> CGPoint
// 获取触发手势的触摸数
    open var numberOfTouches: Int { get }
  • 除了以上的几个属性外还有一些属性也十分重要
// 默认为 true,当为 true 的时候,当适当的视图和手势接收器接收到了触摸之后会发送touchesCancelled给适当的视图,以取消
视图对该触摸的响应,该触摸也就不会继续在事件传递链传递下去。设置为 false 则不会终止事件的传递
    open var cancelsTouchesInView: Bool
// 默认为 false ,当为false 的时候,手势接收器会先捕捉到该触摸,然后发送给适当的视图,两者适当做出相应
        当设置为 true 的时候,手势识别器在识别的过程中,不会将触摸传递给视图,只有当识别失败之后才会传递给适当的视图,此时延时大概0.15ms
    open var delaysTouchesBegan: Bool
// 默认是 true 这种情况下发生一个touch时,在手势识别成功后,发送给touchesCancelled消息给适当的视图,手势识别失败时,会
延迟大概0.15ms,期间没有接收到别的touch才会发送touchesEnded。如果设置为NO,则不会延迟,即会立即发送touchesEnded以结束当前触摸。
    open var delaysTouchesEnded: Bool

// 参考资料
  • 手势状态
public enum UIGestureRecognizerState : Int {
    case possible    // 默认的状态,这个时候的手势并没有具体的情形状态
    case began       // 手势开始被识别的状态
    case changed     // 手势识别发生改变的状态
    case ended       // 手势识别结束,将会执行触发的方法
    case cancelled   // 手势识别取消
    case failed      // 识别失败,方法将不会被调用
    public static var recognized: UIGestureRecognizerState { get } 
}
  • 代理方法
// 手指触摸屏幕后回调的方法,返回NO则不再进行手势识别,方法触发等
    optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
// 是否接受手势 true 为接受
    optional public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
// 是否支持多手势触发,返回YES,则可以多个手势一起触发方法,返回NO则为互斥
    optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
// 下面这个两个方法也是用来控制手势的互斥执行的
// 这个方法返回YES,第一个手势和第二个互斥时,第一个会失效
    optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool
// 这个方法返回YES,第一个和第二个互斥时,第二个会失效
    optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool
// ios9之后推出,目前作用不明,请大佬指导一下
    optional public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive press: UIPress) -> Bool
  • UIPanGestureRecognizer 拖拽手势
  • 在创建一个需要跟随手指滑动而滑动的视图的时候在手势的action 中注意如下几点
  • 获取 pan 手势相对于 pan.state == .begin 的位置
let panGesOffset = pan.translate(in:view)
  • 设置要被滑动的视图的位移
self.center.x += position.x
    self.center.y += position.y
//or
    self.transform = self.transform.translatedBy(x:position.x , y: position.y)
//注意如果需要用到视图经过 transform 之后的 width 的话,就需要用 frame.width 而不能用 bounds.width 并且经过 transform 之后的的 center 是始终不变的
  • 将 panGes 的 translate 置零
// 由于 translate 是相对于 state==.begin 的位置,所以在每次的 pan 动作结束之后都需要为 translate 置零
    panGes.setTranslation(CGPoint.zero, in: self)
  • UITapGestureRecognizer 敲击
  • 创建
let tapGes = UITapGestureRecognizer(target: self, action: #selector(tapGesAction(_:)))
    tapGes.delegate = self
    tapGes.addTarget(self, action: #selector(anohterGesAction))
    view.addGestureRecognizer(tapGes)
// 方法
@objc func tapGesAction(_ tapGes : UITapGestureRecognizer){
        print("tapGesLocation\(tapGes.location(in: view))")
    }
  • UIPinchGestureRecognizer 捏合,用于缩放
  • 注意点
// ges.scale 是相对于最初大小的缩放倍数
  • 示例 : 缩放视图
// 创建缩放手势
        let pinchGes = UIPinchGestureRecognizer(target: self, action: #selector(pinchGesAction(_ :)))
        pinchTestView.addGestureRecognizer(pinchGes)
// 方法
    @objc func pinchGesAction(_ ges : UIPinchGestureRecognizer){
        print(#function)
        // 实现缩放
        // 获取到的 scale 都是默认相对于最开始的大小
        let scale = ges.scale
        pinchTestView.transform = pinchTestView.transform.scaledBy(x: scale, y: scale)
        // 复位
        ges.scale = 1

    }
  • UISwipeGestureRecognizer 轻扫
  • 注意点
// 读取轻扫手势是有一个默认的方向的 : 从左向右,默认情况下只能读取这个手势
// 改变读取的手势方向 swip.direction
// 一个轻扫手势只能设定一个轻扫方向,如果一个控件需要监听多个方向的事件,这个时候就需要添加多个手势。
  • 示例 : 轻扫移动视图
// 创建轻扫手势
        let swipeGes = UISwipeGestureRecognizer(target: self, action: #selector(swipeGesAction(_:)))
        // 设置轻扫方向
        swipeGes.direction = .down
        swipeTestView.addGestureRecognizer(swipeGes)
// 方法
@objc func swipeGesAction(_ ges : UISwipeGestureRecognizer){
        swipeTestView.transform = swipeTestView.transform.translatedBy(x: 10, y: 0)
    }
  • UIRotationGestureRecognizer 旋转
  • 注意点
// ges.rotation 获取到的旋转角度是以触发动作的初始位置来计算的,所以旋转视图完毕之后要置零
  • 示例 : 旋转视图
// 创建缩放手势
        let rotationGes = UIRotationGestureRecognizer(target: self, action: #selector(rotationGesAction(_:)))
        self.swipeTestView.addGestureRecognizer(rotationGes)
// 方法
@objc func rotationGesAction(_ ges : UIRotationGestureRecognizer){
        let rotation = ges.rotation
        swipeTestView.transform = swipeTestView.transform.rotated(by: rotation)
        // 置零
        ges.rotation = 0
    }
  • UILongPressGestureRecognizer 长按
  • 注意点
// 由于在长按的时候可能长按手势会被触发多次,所以在其触发事件中需要判断手势的一个状态
// longPress.state
  • 示例 : 长按显示 UIMenuController
// 创建长按手势
        let longPressGes = UILongPressGestureRecognizer(target: self, action: #selector(labelLongPressAction(_:)))
        // 长按手势最小触发时间
        longPressGes.minimumPressDuration = 1
        // 需要点击的次数
        //        longPressGes.numberOfTapsRequired = 1
        // 长按手势需要的同时敲击触碰数(手指数)
        longPressGes.numberOfTouchesRequired = 1
        // 长按有效移动范围(从点击开始,长按移动的允许范围 单位 px
        longPressGes.allowableMovement = 15

        label.isUserInteractionEnabled = true
        label.addGestureRecognizer(longPressGes)
// 方法  关于 UIMenuController 具体请看上一篇博客
// 
@objc func labelLongPressAction( _ sender : UILongPressGestureRecognizer){
        // 如果 Menu 已经被创建那就不再重复创建 menu
        if (UIMenuController.shared.isMenuVisible){
            return
        }
        // 注意:长安手势可以触发两次事件,我们需要判断手势状态,如下
//        if (sender.state == .ended) {
            // 要成为第一响应者否则某些功能会错乱,例如 label 未成为第一响应者但是 label 的 menu 有 paste 功能会直接 paste 到第一响应者上
//            label.becomeFirstResponder()
            // 由于系统只允许一个 UIMenuController 存在,所以创建 UIMenuController 是以单例的形式获取的
            let menu = UIMenuController.shared

            // 设置 Menu 所显示的 items
            menu.menuItems = [UIMenuItem(title: "item1", action: #selector(objAction)),
                              UIMenuItem(title: "item2", action: #selector(objAction)),
                              UIMenuItem(title: "item3", action: #selector(objAction)),
                              UIMenuItem(title: "item4", action: #selector(objAction))]

            // 设置箭头方向
            menu.arrowDirection = .default

            // 设置添加上 menu 的目标控件的 rect 和目标控件
            menu.setTargetRect(label.bounds, in: label)
            // 令 Menu 可见
            menu.setMenuVisible(true, animated: true)
//        }
    }

swiftui 重启app swift recovery_手势识别

  • UIScreenEdgePanGestureRecognizer 屏幕边缘平移 手势
  • 注意点
//1. 视图位置(屏幕边缘)
    //2. 设置edges属性
     // 设置屏幕边缘手势支持方法
  // 需要添加到控制器的根视图上才能生效
  • 示例
// 创建边缘平移手势
        let edgeGes = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(edgeGesAction(_:)))
        edgeGes.edges = .left
        view.addGestureRecognizer(edgeGes)
// 方法
@objc func edgeGesAction(_ ges : UIScreenEdgePanGestureRecognizer){
        swipeTestView.transform = swipeTestView.transform.translatedBy(x: 0, y: 20)
    }

参考资料 :

http://www.cocoachina.com/ios/20130501/6108.html
http://www.jianshu.com/p/5aca8a413d40
http://www.jianshu.com/p/4ac617c9493b