Swift UIGestureRecognizer介绍

来源:互联网 发布:mac优酷客户端 编辑:程序博客网 时间:2024/05/02 04:46
  • 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// 参考资料   http://blog.csdn.net/fys_0801/article/details/50605837
  • 手势状态
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 具体请看上一篇博客// http://blog.csdn.net/eiamor/article/details/78235796@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)//        }    }

这里写代码片

  • 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)    }

参考资料 :
https://my.oschina.net/u/2340880/blog/527077
http://www.cocoachina.com/ios/20130501/6108.html
http://www.jianshu.com/p/5aca8a413d40
http://www.jianshu.com/p/4ac617c9493b
http://blog.csdn.net/fys_0801/article/details/50605837

原创粉丝点击