iOS应用开发过程,合理的使用手势识别功能来响应用户的操作,能够很好提升用户体验,为App增色。下面对UIGestureRecognizer手势进行一个比较全面的描述:
1、UIGestureRecognizer介绍
UIGestureRecognizer是手势识别的一个抽象类,没法直接使用。好心的苹果大神们已经为我们实现了常用的一些手势识别子类,具体列表如下:
- UITapGestureRecognizer
- UIPinchGestureRecognizer
- UIRotationGestureRecognizer
- UISwipeGestureRecognizer
- UIPanGestureRecognizer
- UIScreenEdgePanGestureRecognizer(iOS7.0以后)
- UILongPressGestureRecognizer
1.1、UITapGestureRecognizer介绍
用以识别用户使用单指或多指在某个View中点击一次或多次的动作。UITapGestureRecognizer除了包含继承自父类的属性外,还有两个自有属性:
numberOfTapsRequired: 表示点击的次数,当连续点击次数未达到指定数量时,不作响应,默认值为1。
numberOfTouchesRequired: 表示需同时点击的手指数量,默认值为1。
1.2、UIPinchGestureRecognizer介绍
用以识别用户使用两指在某个View中向外或向内滑动动作,平时多用于缩放。UIPinchGestureRecognizer除了包含继承自父类的属性外,还有两个自有属性:
scale:表示缩放率
velocity:表示缩放率对应的每秒速率(只读)
1.3、UIRotationGestureRecognizer介绍
用以识别用户使用两指在某个View中旋转动作。UIRotationGestureRecognizer除了包含继承自父类的属性外,还有两个自有属性:
rotation: 表示旋转的弧度
velocity:表示旋转弧度对应的每秒速率(只读)
1.4、UISwipeGestureRecognizer介绍
用以识别用户使用手指在某个View中的滑动动作,即快速移动。UISwipeGestureRecognizer除了包含继承自父类的属性外,还有两个自有属性:
direction:表示滑动方向,向左、向右、向上、向下共四个方向
numberOfTouchesRequired:表示需同时滑动的手指数量,默认值为1。
1.5、UIPanGestureRecognizer介绍
用以识别用户使用单指或多指在某个View中慢速移动动作。UIPanGestureRecognizer除了包含继承自父类的属性外,还有两个自有属性:
minimumNumberOfTouches:表示最小手指数量,默认值为1
maximumNumberOfTouches:表示最大手指数量,默认值为无符号整型的最大值
1.6、UIScreenEdgePanGestureRecognizer介绍
继承自UIPanGestureRecognizer,只是需要指定拖动动作的起始点距离屏幕边缘的位置。UIScreenEdgePanGestureRecognizer除了包含继承自父类的属性外,还有一个自有属性:
edges:手势起始的位置区域
1.7、UILongPressGestureRecognizer介绍
用以识别用户使用单指或多指在某个View中长按的动作。UILongPressGestureRecognizer除了包含继承自父类的属性外,还有四个自有属性:
minimumPressDuration:最短按下的时间,默认值为0.5秒。
numberOfTouchesRequired:表示需同时滑动的手指数量,默认值为1。
numberOfTapsRequired:表示点击的次数,默认值为1。
allowableMovement:表示长按过程中手指允许移动的长度,计量单位为像素点,默认值为10像素点
2、UIGestureRecognizer使用通用步骤
UIGestureRecognizer使用非常简单,只需要两步即可完成:
A、创建UIGestureRecognizer使用实例,指定对应的回调方法,此处以UITapGestureRecognizer为例说明
- //创建UITapGestureRecognizer实例对象
- let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "handlePan:")
- func handlePan(sender: UITapGestureRecognizer) {
- print("get tap gesture")
- }
B、将
UIGestureRecognizer实例对象添加进指定的View。一个手势只能对应一个View,但是一个View可以有多个手势
- self.view.addGestureRecognizer(tapGesture)
多个View,只需向同一个View中继续添加
UIGestureRecognizer实例对象即可
- self.view.addGestureRecognizer(rotationGesture)
3、自定义手势
自定义手势需要继承UIGestureRecognizer类,并实现下面的方法
- - touchesBegan:withEvent: //手势开始,当用户单指或多指触碰到屏幕
- - touchesMoved:withEvent: //手势移动,当用户单指或多指在屏幕上移动
- - touchesEnded:withEvent: //手势结束,当用户手指离开屏幕
- - touchesCancelled:withEvent: //手势取消,如系统内存不足导致的取消等
下面的例子为自定义的Tap手势实现代码,仅供学习之用
- //
- // CustomTapGestureRecoginizer.swift
- // Gest
- //
- // Created by jimi on 15/12/28.
- // Copyright © 2015年 jimi. All rights reserved.
- //
-
- import UIKit
- import UIKit.UIGestureRecognizerSubclass
-
- class CustomTapGestureRecoginizer: UIGestureRecognizer {
- var numberOfTapsRequired: Int = 1
- var numberOfTouchesRequired: Int = 1
-
- var firstLocation: CGPoint = CGPointZero
-
- override init(target: AnyObject?, action: Selector) {
- super.init(target: target, action: action)
- }
-
- override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent) {
- super.touchesBegan(touches, withEvent: event)
- if touches.count != self.numberOfTouchesRequired {
- self.state = UIGestureRecognizerState.Failed
- }
-
- if let touch: UITouch = touches.first {//得到手指点击的起始位置
- self.firstLocation = touch.locationInView(self.view)
- }
- }
-
- override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent) {
- super.touchesMoved(touches, withEvent: event)
- if let touch: UITouch = touches.first {
- let currentPoint: CGPoint = touch.locationInView(self.view)
- if abs(currentPoint.x - self.firstLocation.x) >= 10 {//当手势有移动时,判断手势异动距离是否已经大于10个点,如果大于10个点即为非点击事件了
- self.state = UIGestureRecognizerState.Failed
- }
- }
- }
-
- override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent) {
- super.touchesEnded(touches, withEvent: event)
- self.firstLocation = CGPointZero
-
- self.state = UIGestureRecognizerState.Ended //手势识别成功,将状态标记为识别成功
- }
-
- override func touchesCancelled(touches: Set<UITouch>, withEvent event: UIEvent) {
- super.touchesCancelled(touches, withEvent: event)
- self.firstLocation = CGPointZero
- }
- }
4、UIGestureRecognizer进阶
4.1 UIGestureRecognizer状态说明
此处借用一下苹果官方文档的图片,:)
图片左半边是离散手势(如点击事件)的状态变迁图,右半边是连续事件(如滑动)状态变迁图。任何事件都是从Possible(可能的)的状态开始,经过必要的事件之后,转变成Failed(失败)、Canceled或Recognized(可识别)状态,即手势识别结束。
- 离散事件缺少中间的Changed(正在变化的)中间状态,直接从事件的Began到结束状态Failed或Recognized
- 连续事件中的Changed不停的标记当前正在发生的事件的状态,如滑动事件,会一直记录当前手势移动的位置,对应于代码中touchesMoved
- 当手指离开屏幕,表示手势事件结束。此时需要识别结束后的事件是否满足既定的手势识别条件。如移动的距离和速度等是否满足要求,如果满足即表示识别成功(Recognized),否则表示识别失败(Failed);若中途遭遇其他系统事件中断(如内存不足),即表示手势识别事件被取消(Canceled)。
4.2 多手势识别顺序问题
前面我们已经简单提到过,同一个View可以包含多个手势,但是一个手势只能对应一个View。如果在同一个View中包含了多个手势,在iOS系统默认情况下,没有任何顺序可言,这就是通常所说的手势冲突问题。好在苹果允许我们修改手势的部分默认行为方式:
- 两个具有部分包含关系的手势,可以通过指定识别顺序来解决手势冲突问题;
如:panRecognizer.requireGestureRecognizerToFail(swipeRecognizer)
rotationGesture.requireGestureRecognizerToFail(panGesture)
这个需要实现手势代理方法gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法,在该方法中返回YES(true)即可
- 指定两个手势之间的阻止关系,如手势A响应时,不响应手势B,但是手势B响应时,需要响应手势A
panRecognizer.canPreventGestureRecognizer(pinchGestureRecognizer)