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