演示机型:Iphone 12系统版本:iOS14
1、打开手机设置按钮。
2、在设置界面中点击“通用”。
3、在通用界面中点击“辅助功能”。
4、接着选择“便捷访问”,点击“辅助触控”。
5、点击“辅助触控”并打开,点击“自定顶层菜单”。
6、点击“+”图标。
7、在自定顶层菜单中点击“加”图标,然后在功能区中选择“手势”即可。
触摸事件一共有4个,一次完整的触碰,至少包括开始和结束两个事件
1 >触摸开始 ,用手指(一根或者多根)按在屏幕上
2>触摸移动 , 手指在屏幕上发生移动(有可能发生)
3>触摸结束,手指从屏幕上离开
4>触摸被取消,因为系统事件(比如电话)一次触摸事件被取消
属性:
1>view : 监测到触摸事件的视图,在开发中使用最为频繁的属性
2 >window : 窗口 ,发生触碰事件的窗口
3 >phase: 相位属性 ,在开发中使用很少,一般是用户自定义手势识别
4 >timestamp : 发生触摸的时间以上两个属性, 很少用到,一般都是自定义的手势
5 >tapcount :发生触摸时,在短时间时间内,手指点按的次数
方法 :
1 >locationInView : 发生触摸事件性对视图的位置
2 >previousLocationI女IE我: 发生触摸事件前一次手指所在的位置
1 > 发生触摸事件后,系统会将改事件加入到一个由UIApplication管理的事件队列中
2 >UIApplication会从事件队列中取出最前面的事件并将其分发以便处理,通常先发送事件给应用程序的主窗口
3>主窗口会调用hitTest:withEvent:方法在视图继承树中找到一个最合适的子视图来处理触摸事件,该子视图即为hit-test视图
4>如果hit-test视图不处理收到的事件消息,UIKit则将事件转发到响应者链中的下一个响应者,看其是否能对该消息进行处理
5>接收用户触摸响应的几个条件
1) self.userInteractionEnabled =YES允许接收用户响应
2) self.hidden = NO只有现实的视图才能接收用户触摸
3) self.alpha >0.01视图的透明度一定要可见
提示:并不是所有的控件都默认接收用户交互的,譬如:UIImageView,UILabel等
6>参数说明
point 用户触摸的点,相对于当前视图坐标系的坐标点
event 用户触摸事件,开发中一般程序员不使用,该事件用于在响应者链条上传递
1>实例化手势识别 UITapGestureRecognizer()
2>设置手势识别属性 addTarget(target:AnyObject, action: Selector)
3>将手势识别附加到指定的视图 view.addGestureRecognizer()
4>编写监听方法
1>UIGestureRecognizer 所有手势识别的父类,不允许直接使用,可以用来自定义手势
UITapGestureRecognizer(点按)
UIPinchGestureRecognizer(捏合)
UIPanGestureRecognizer(拖动)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)
1>UITapGestureRecognizer 点按手势(离散手势,其他手势都是连续手势)
属性:
numberOfTapsRequired点击次数,单击双击
numberOfTouchesRequired 手指根数
2>UILongPressGestureRecognizer 长按手势
3>UIPanGestureRecognizer 拖动手势
属性:不常用
方法:
在视图中拖动的距离
public func translationInView(view: UIView?) ->CGPoint
在视图中拖动的速度,通常可用于模拟惯性,需要一些物理方面的计算
public func velocityInView(view: UIView?) ->CGPoint
拖动手指中的平移距离是相对于初始位置,如果使用CGAffineTransformTranslate累加形变方法
需要在每次位移之后,重置recognizer的位移量,就是将位移量清零
4>UIPinchGestureRecognizer 捏合手势
属性:
scale 比例
velocity 捏合速度,不常用
5>UIRotationGestureRecognizer 旋转手势
属性:
rotation 旋转角度
velocity 旋转速度,不常用
在形变时,iOS采取就近原则旋转,如果不能按照希望的方向旋转,可以增加一些修正值,例如0.01
直接通过形变属性,要实现一次性转一圈,比较困难,可以分两次进行
6>UISwipeGestureRecognizer 轻扫手势,通常添加到根视图上
属性:
numberOfTouchesRequired
参与轻扫手势的手指根数
direction
轻扫的方向
提示:
1) 如果要检测几个方向的轻扫,需要分别实例化几个轻扫手势
2) 轻扫手势虽然是连续手势,但是不需要去处理UIGestureRecognizerStateChanged状态
因为是在手指离开屏幕后,该手势才被识别的。
public enum UIGestureRecognizerState : Int {
// 没有触摸事件发生,所有手势识别的默认状态
case Possible
// 一个手势已经开始但尚未改变或者完成时
case Began
// 手势状态改变
case Changed
// 手势完成
case Ended
// 手势取消,恢复至Possible状态
case Cancelled
// 手势失败,恢复至Possible状态
case Failed
// 识别到手势识别
public static var Recognized: UIGestureRecognizerState { get }
}
注意:对于一个手指的触摸,是UITouch每次状态改变的时候都会回调UIResponder相对应的处理方法。对于多个手指的触摸,也许多个UITouch状态的改变一起回调UIResponder的处理方法,也许每个UITouch状态的改变都会回调UIResponder的处理方法,例如,两个点击,可能只有一个touchesBegan的回调,两个touchesEnded的回调.同时,多个UIControl状态改变只有一次touchesBegan等方法回调的参数touches里touch的个数我测试的时候只有一个,不要以为所有状态改变的UITouch只有一次回调时都会放到touches参数里。关于多点触摸的处理个人不建议在UITouch的响应机制里去做处理,里面具体原理并不明朗,实际开发中的借鉴也不多,涉及多点触摸使用手势更好。
UIResponder是iOS中用于处理用户事件的API,可以处理触摸事件、按压事件(3D touch)、远程控制事件、硬件运动事件。可以通过touchesBegan、pressesBegan、motionBegan、remoteControlReceivedWithEvent等方法,获取到对应的回调消息。UIResponder不只用来接收事件,还可以处理和传递对应的事件,如果当前响应者不能处理,则转发给其他合适的响应者处理。
应用程序通过响应者来接收和处理事件,响应者可以是继承自UIResponder的任何子类,例如UIView、UIViewController、UIApplication等。当事件来到时,系统会将事件传递给合适的响应者,并且将其成为第一响应者。
第一响应者未处理的事件,将会在响应者链中进行传递,传递规则由UIResponder的nextResponder决定,可以通过重写该属性来决定传递规则。当一个事件到来时,第一响应者没有接收消息,则顺着响应者链向后传递。
Gesture Recognizer 是对底层事件处理的封装,是为了让使用者能够更简单处理事件。
手势分为离散型手势(discrete gestures)和持续型手势(continuous gesture)。
手势响应过程:
手势状态:
UIControl是系统提供的能够以target-action模式处理触摸事件的控件,iOS中UIButton、UISegmentedControl、UISwitch等控件都是UIControl的子类。
值得注意的是,UIConotrol是UIView的子类,因此本身也具备UIResponder应有的身份。
UIControl作为控件类的基类,它是一个抽象基类,我们不能直接使用UIControl类来实例化控件,它只是为控件子类定义一些通用的接口,并提供一些基础实现,以在事件发生时,预处理这些消息并将它们发送到指定目标对象上。
UIControl的触发过程:
四个重要识别方法是在touchesBegan、touchesMoved、touchedEnded、touchesCancelled里回调的。
推测是:endTrackingWithTouch调用后识别了行为,做标记,返回到touchesEnded后,判断本UIControl是否易识别行为,调用行为回调。
App接收到触摸事件后,会被放入当前应用程序的UIApplication维护的事件队列中.
由于事件一次只有一个,但是能够响应的事件的响应者众多,所以这就存在一个寻找第一响应者的过程。
调用方法,获取到被点击的视图,也就是第一响应者。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
hitTest:withEvent:方法内部会通过调用pointInside:这个方法,来判断点击区域是否在视图上,是则返回YES,不是则返回NO。
经过Hit-Testing的过程后,UIApplication已经知道了第一响应者是谁,接下来要做的事情就是:
自定义的view的touchesBegan、touchesMoved、touchesEnded、touchedCancelled四个方法重写,记录打印过程,该view上添加tapGestureRecognized手势,该tapGestureRecognized也覆写了这四个方法。
点击view调用打印过程输出:
调用栈:
结合上面的输出和调用栈,我们可能并不能明确的看出有手势的时候点击的过程,不过如果你自己调试,是能得出如下结论的:
UIGestureRecognizer和UITouch的关系可以由UIGestureRecognizer的三个属性影响:cancelsTouchesInView、delaysTouchesBegan、delaysTouchesEnded。
本身就是在UIResponder的UITouchesBegan、UITouchesMoved、UITouchedEnded、UITouchesCancel四个回调中调用的。
UIControl的响应处理并不会影响UIResponder的响应链的处理,但是UIControl会影响另一个UIControl,子视图的UIControl具有优先级。
UIGestureRecognizer和UIControl并没有决定的优先级。
从iOS6开始在控件的父视图上面添加相应的手势,控件就会控制阻止手势行为,比如:
tap 手势在 UIButton,UISwitch,UIStepper,UISegmentControl,UIPageControl;
swipe 手势在 UISlider;
pan 手势在 UISwitch;
其他可能是手势优于控件的行为。
UIResponder有touchesBegan等四个方法,默认向superview传递。
所有需要自定义点击处理逻辑的UIResponder子类要覆盖这四个方法。
点击事件由四个方法处理。
UIButton的处理也是需要经过这四个方法。
UIGestureRecognizer也有touchesBegan等四个方法。
手势不在响应链里,但是也会观察它的view和subView的点击。
UIGestureRecognizer会影响UIResponder的四个响应点击的方法。
默认点击事件响应关键步骤说明:
1)用户手指点击屏幕,经过系统传递到UIApplication, UIApplication通过hitTest:方法找到对应UITouch发生的第一响应者view
2)UIApplication更新手势状态,从第一响应者上的手势到其视图层上所有先辈视图上的手势都会接收这个UITouch来更新手势状态
3)UIApplication将UITouch交给找到的第一响应着view处理
4)UIApplication更新手势状态,识别成功后,会向UITouch的第一响应者发送cancel方法
加上UIControl会让过程变得复杂,关于UIControl的原理,不清楚,也不敢妄下结论,依据网上和实际测试大致推断:
1)它不会影响UITouch本身的响应流程,但是会影响其他UIControl和UIGestureRecognizer的响应
2)自定义的UIControl是和UITouch本身的响应过程是一样的
3)系统定义的UIControl和UIGestureRecognizer同一个优先级,谁先识别出来,另一个就out了,但是UIControl和UIGestureRecognizer有一点不同,它并不会cancel UITouch的流程。
关于UITouch、UIGestureRecognizer、UIControl之间影响说明:
1)UITouch和UIGestureRecognizer:UIGestureRecognizer优先级高于UITouch,由UIGestureRecognizer的三个参数cancelsTouchesInView、delaysTouchesBegan、delaysTouchesEnded决定对UITouch的影响,默认情况下,UIGestureRecognizer识别成功后,会向UITouch发送cancel
避免:
1)尽量不要覆盖重写UIResponder的touchesBegin、touchesMoved、touchesCancelled、touchesEnded这四个方法,如果需要覆盖重写,逻辑应该尽量简单,不宜做复杂的处理,
2)不要自定义UIControl,直接使用系统定义的UIControl
3)UIControl上不要添加UIControl子视图
4)不要依赖UIGestureRecognizer的delayTouchBegin和delayTouchEnded
5)不要自定义UIGestureRecognizer
参考文章:
1) iOS 事件(UITouch、UIControl、UIGestureRecognizer)传递机制
2) Touch Event Handing 教学 — part 1
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)