iOS学习笔记(2)— UIView用户事件响应

  

iOS学习笔记(2)— UIView用户事件响应

UIView除了负责展示内容给用户外还负责响应用户事件。本章主要介绍UIView用户交互相关的属性和方法。

  1、交互相关的属性

  userInteractionEnabled 默认是YES ,如果设置为NO则不响应用户事件,并且把当前控件从事件队列中删除。也就是说设置了userInterfaceEnabled属性的视图会打断响应者链导致该view的subview都无法响应事件。

  multipleTouchEnabled  默认是NO,如果设置为YES则支持多点触碰。

  exclusiveTouch 默认是NO,如果设置为YES则当前UIView会独占整个Touch事件。具体来说就是如果UIView设置了exclusiveTouch属性为YES则当这个UIView成为第一响应者时,在手指离开屏幕前其他view不会响应任何touch事件。

  作用举例:UITableView的每个cell都需要使用exclusive,否则同时点击多个cell会触发每个视图的事件响应。手势识别会忽略此属性。

  2、触摸响应

  了解UIView的触碰响应之前,首先了解在iOS中触碰事件是什么,事件在视图模型中是如何传递的,视图在接收到一个事件是如何响应的。下面介绍触碰事件类UITouch和响应者链来解释事件的工作原理。

  在iOS中UITouch类代表触碰事件。当用户触摸屏幕后就会产生相应的事件,所有相关的UITouch对象都被包装在事件中,被程序交由特定的对象处理。UITouch对象包括触碰的详细信息。

  UITouch含有5个属性:

  window:触碰产生时所处的窗口,由于窗口可能发生变化,当前所在的窗口不一定是最开始的窗口。

  view:触碰产生时所处的视图。由于视图可能发生变化,当前视图也不一定是最初的视图。

  tapCount:短时间内轻击(tap)屏幕的次数,可根据tapCount判断单击、双击或更多的轻击。

  timestamp:时间戳记录了触碰事件产生或变化时的时间。单位是秒。

  phase:触碰事件在屏幕上有一个周期,即触碰开始、触碰点移动、触碰结束,中途取消。通过phase可以查看当前触碰事件在一个周期中所处的状态。UITouchPhase枚举:

  UITouchPhaseBegan

  UITouchPhaseMoved

  UITouchPhaseStationary

  UITouchPhaseEnded

  UITouchPhaseCancelled

  当手指触碰到屏幕,无论是单点还是多点触碰,事件都会开始,直到用户所有的手指都离开屏幕。期间所有的UITouch对象都被封装在UIEvent事件对象中,由程序分发给处理者。事件记录了这个周期中所有触碰对象状态的变化。

  只要屏幕被触摸,系统会将诺干个触碰信息封装到UIEvent对象中发送给程序,由管理程序UIApplication对象将事件分发。

  响应者对象就是可以响应事件并对事件作出处理的对象。在iOS中UIResponder类定义了响应者对象的所有方法。UIApplication、UIWindow、UIViewController、UIView以及UIKit中继承自UIView的控件都间接或直接继承自UIResponder类,这些类都可以当做响应者。

  响应者链表示一系列响应者对象组成的事件传递的链条。当确定了第一响应者后,事件交由第一响应者处理,如果第一响应者不处理事件沿着响应者链传递,交给下一个响应者。一般来说,第一响应者是UIView对象或者UIView的子类对象,当其被触摸后事件交由它处理,如果它不处理,事件就会交给它的UIViewController处理(如果存在),然后是它的superview父视图对象,以此类推,直到顶层视图。如果顶层视图不处理则交给UIWindow对象处理,再到UIApplication对象(如果UIApplication继承自UIResponder)。如果整个响应者链都不响应这个事件则该事件被丢弃。

  UIView类继承了UIResponder类,要对事件作出处理还需要重写UIResponder类中定义的事件处理函数。根据不同的触碰状态,程序会调用相应的处理函数,这些函数包括:

  -(void) touchesBegan:(NSSet *)touches withEvents:(UIEvent *)event;

  -(void) touchesMoved:(NSSet *)touches withEvents:(UIEvent *)event;

  -(void) touchesEnded:(NSSet *)touches withEvents:(UIEvent *)event;

  -(void) touchesCancelled:(NSSet *)touches withEvents:(UIEvent *)event;

  这几个方法被调用时,对应了UITouch类中的phase属性的4个枚举值。当触碰被取消,如触碰过程中被来电打断,会调用touchesCancelled:touches:方法。

  这些方法在开发中并不需要全部实现,可以根据需要重写特定的方法。这4个方法都有两个相同的参数:NSSet类型的touches和UIEvent类型的event。Touches表示触碰产生的所有的UITouch对象,event表示事件。因为UIEvent包含了整个触碰过程中所有的触碰对象,所以可以调用allTouches 方法获取该事件内所有触碰对象,也可以调用touchesForView;或者touchesForWindows;取出特定视图或者窗口上的触碰对象。在这几个事件中,都可以拿到触碰对象,然后根据其位置、状态、时间属性做逻辑处理。

  轻击操作很容易引起歧义,比如用户点击了一次之后,并不知道用户是想单击还是只是双击的一部分,或者点了两次之后并不知道用户是想双击还是继续点击。可以使用延迟调用函数解决这个问题。

  

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

  UITouch *touch = [touches anyObject];

          if (touch.tapCount == 1)

         {

                 [self performSelector:@selector(setBackground:) withObject:[UIColor blueColor] afterDelay:2];

          }

          else if(touch.tapCount == 2)

          {

                 [self cancelPreviousPerformRequestsWIthTarget:self              selector:@selector(setBackground:) object:[UIColor blueColor]];

                 self.view.backgroundColor = [UIColor redColor];

           }

  }   

  

  除了触碰事件外UIResponder还提供了运动事件的支持。

  运动事件的方法:

  -(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event 摇动事件开始

  -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event 摇动事件结束

  -(void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event  摇动事件被中断

  远程事件:

  -(void)remoteControlReceivedWithEvent: 音乐后台播放控制的时候会用到

  第一响应者的相关函数:

  - (BOOL)canBecomeFirstResponder    默认返回NO

  - (BOOL)becomeFirstResponder

  - (BOOL)canResignFirstResponder    默认返回YES

  - (BOOL)resignFirstResponder;

  - (BOOL)isFirstResponder

  可以通过becomeFirstResponder方法注册成为第一响应者,通过resignFirstResponder方法不成为第一响应者。比如通过这两个方法操作UITextField来控制键盘的现隐藏。

  3、手势

  属性:

  NSArray *gestureRecognizers 

  可以通过这个属性获取当前UIView的所有手势对象。手势在触碰事件处理流程中,处于观察者的角色,其不是view层级结构的一部分,所以不参与响应者链。在将触摸事件发送给hit-test view之前,系统会先将触碰事件发送到view绑定的Gesture Recognizer上。

  UIView关于手势的方法:

  -(void) addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer  增加一个手势。

  -(void) removeGestureRecognizer:(UIGestureRecognizer *)getureRecognizer 删除一个手势。

  -(BOOL) gestureRecognizerShouldBegan:(UIGestureRecognizer *)gestureRecognizer 询问是否开始执行该手势,默认返回YES。

  手势相比触碰事件的好处是可以直接使用已经定义好的手势,开发者不用自己计算手指移动轨迹。手势识别的基类是UIGestureRecognizer,是一个抽象类,定义了实现底层手势识别行为的编程接口。衍生类如下:

  UITabGestureRecognizer         轻击手势

  UIPinchGestureRecognizer       捏合手势

  UIRotationGestureRecognizer    旋转手势

  UISwipeGestureRecognizer  轻扫手势

  UIPanGestureRecognizer 拖拽手势

  UILongPressGestrueRecognizer 长按手势

  UIGestureRecognizer主要方法:

  -(id) initWithTarget:action: 初始化方法

  -(void)addTarget:action:  

  -(void)removeTarget:action: 

  主要属性:

  UIGestureRecognizerState state 手势识别当前状态

  有以下几种情况:

  UIGestureRecognizerStatePossibel,  未识别状态

  UIGestureRecognizerStateBegan,     手势开始

  UIGestureRecognizerStateChanged,  手势改变

  UIGestureRecognizerStateEnded, 手势结束

  UIGestureRecognizerStateFailured 手势失败,被其他事件中断。当把手势state设为这个值得时候相当于取消了这个手势。

  cancelsTouchesInView 为YES时,表示当Gesture Recognizers识别到手势后,会向hit-test view发送touchesCancelled:消息以取消hit-test view对触碰序列的处理,这样只有Gesture Recognizer响应此次触碰,响应者链的view不再响应。如果为NO,则不发送touchesCancelled:消息,这样Gesture Recognizer和view同时响应触碰事件。默认值是YES。

  delaysTouchesBegan 为NO时表示触碰序列已经开始而手势识别还未识别出此手势时,touch事件会同时发给hit-test view。如果为YES,则手势在识别过程中,不会有任何触碰事件发送给hit-test view;如果手势识别器最终识别了手势,则也不会发送任何消息给hit-test view;如果手势识别器最终没有识别到手势,才会发送所有触碰事件给view处理。默认值是NO。

  delaysTouchesBegan 为YES时,延迟发送touchesEnded:消息,手势失败时才发送。默认值是YES。

  

  UITabGestureRecognizer  轻击手势任意手指任意次数的点击

  属性:

  numberOfTapsRequired 点击次数

  numberOfTouchesRequired 手指个数

  UIPinchGestureRecognizer  捏合或者扩张手势

  属性:

  scale:初始值为1,两手指距离减少则scale不断变小;两个手指重合则变为0;

  velocity:初始值为0,手指移动的相对速度,两手指距离减少为负数,速度越快数值越少;两手指距离变大为整数,速度越快数值越大。

  UIRotationGestureRecognizer 旋转手势

  属性:

  rotation:初始值为0,两手指的旋转弧度,顺时针旋转为正数,逆时针旋转为负数。

  velocity:初始值为0手指一动的相对速度,顺时针为正数越快值越大;逆时针为负越快越小。

  UISwipGestureRecognizer 轻扫手势,一个手势只能指定一个方向,如果需要指定多个方向需要多个手势

  属性:

  numberOfTouchesRequired: 手指个数

  direction:手势方向,如UISwipeGestureRecognizerDirectionRight 向右

  UIPanGestureRecognizer:  拖拽手势,相比轻扫手势,手指与屏幕的交互时间更长。

  属性:

  mininumNumberOfTouches 默认值为1,最少手指数量

  maxnumNumberOfTouches 最大手指数量

  方法:

  - (CGPoint)velocityInView:(UIView *)view  返回拖拽手势的速度,值是每秒移过的point值,被分成水平和垂直两个分量。

  UILongPressGestrueRecognizer: 长按手势。

  属性:

  numberOfTapsRequired:默认值为0,轻击的次数。

  numberOfTouchesRequired:默认值是1,手指数量。

  mininumPressDuration:默认值为0.5,单位是秒。

  allowableMovement:默认值为10,单位是像素pixels。

  多手势兼容

  可以为View添加多个手势,缺省情况下,没有对手势的执行顺序排序,每次调用顺序可能都不同。通过以下方法可以控制手势的响应顺序。

  - (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer

  在作为参数的GestureRecognizer失败以后手势才发生,否则手势从不会发生。

  [self.panRecognizer requireGestureRecognizerToFail:self.swipeRecognizer];  捏合手势失败后才会触发拖拽手势。如果捏合手势成功则拖拽手势永远不会被触发

  - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer

  这个方法可以重载,比如UIGestureRecognizer的子类重载了这个方法返回NO,也就是说无论任何情况下子类的手势都不能被阻止,是非常强势的手势。

  如果返回YES,那么preventingGestureRecognizer传入的手势就会组织子类手势。比如:

  [rotationGestureRecognizer canBePreventedByGestureRecognizer:pinchGestureRecognizer]; 如果rotation手势重载了canBePreventedByGestureRecognizer方法并且返回YES。则旋转手势被捏合手势阻止,但是旋转手势不能阻止捏合手势。

  还可以在方法体中加入逻辑判断。

  - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer

  这个方法同样可以重载,如果返回NO则这个手势不能阻止其他任何手势。

  如果返回YES,就可以阻止preventedGestureRecognizer的手势。比如:

  [rotationGestureRecognizer canPreventGestureRecognizer:pinchGestureRecognizer];  如果rotation手势重载了canBePreventedByGestureRecognizer方法并且返回YES。则旋转手势阻止了捏合手势。

  UIGestureRecognizerDelegate

  - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

  此方法在gesture recognizer视图传出UIGestureRecognizerStatePossible状态时调用,如果返回NO,则转换成UIGestureRecognizerStateFailed;如果返回YES,则继续识别。默认返回YES

  - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

  此方法在window对象有触碰事件发生时,touchesBegan:withEvent:方法之前调用。如果返回NO,则GestureRecognizer忽略此触碰事件。默认返回YES。可以用于禁止某个区域的手势。

  - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

  如果有多个手势接收到了同一个消息,该回调方法决定当前手势是否要响应该事件,如果返回YES则该事件被响应,如果返回NO该事件将被忽略

时间: 2024-08-02 02:31:31

iOS学习笔记(2)— UIView用户事件响应的相关文章

UIView用户事件响应

UIView除了负责展示内容给用户外还负责响应用户事件.本章主要介绍UIView用户交互相关的属性和方法. 1.交互相关的属性 userInteractionEnabled 默认是YES ,如果设置为NO则不响应用户事件,并且把当前控件从事件队列中删除.也就是说设置了userInterfaceEnabled属性的视图会打断响应者链导致该view的subview都无法响应事件. multipleTouchEnabled  默认是NO,如果设置为YES则支持多点触碰. exclusiveTouch 

iOS学习笔记(1)— UIView 渲染和内容管理

iOS学习笔记(1)— UIView 渲染和内容管理 iOS中应用程序基本上都是基于MVC模式开发的.UIView就是模型-视图-控制器中的视图,在iOS终端上看到的.摸到的都是UIView. UIView在屏幕上定义了一个矩形区域和管理区域内容的接口.在运行时,一个视图对象控制该区域的渲染:UIView继承自UIResponder,UIResponder是用来响应事件的类,UIView也具有响应事件的能力.所以说UIView具有三个基本的功能,绘制内容并管理内容的布局,响应用户交互,动画.正是

iOS学习笔记之触摸事件&UIResponder

iOS学习笔记之触摸事件&UIResponder 触摸事件 与触摸事件相关的四个方法如下: 一根手指或多根手指触摸屏幕 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; 一根手指或多根手指在屏幕上移动(随着手指的移动,相关的对象会持续发送该消息) -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; 一根手指或多根手指离开屏幕 -(void)

IOS学习笔记-触摸事件

一.事件传递的过程1.用户手指触摸屏幕,产生一个事件对象 2.系统会将这个事件对象添加到事件队列(先进先出)中 3.由UIApplication取出事件队列中的事件对象进行处理 4.UIApplication会先将事件对象传递给主要的UIWindow(当然,要先检测UIWindow是否能够接收和传递事件) 5.UIWindow会遍历所有的子控件,看看触摸点有没有落在某个子控件上面: 1> 如果触摸点没有落在子控件上,那么就由UIWindow直接处理这个事件,事件传递完毕 2> 如果触摸点落在子

IOS学习笔记 -- Modal和Quartz2D

一. Modal1.Modal的默认效果:新控制器从屏幕的最底部往上钻,直到盖住之前的控制器为止;Modal只是改变了View的现实,没有改变rootViewController 2.常用方法1>.以Modal的形式展示控制器- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion2>.关

iOS学习笔记-精华整理

iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始等待用户的操作,自动释放池就会被释放掉(调用dealloc),池中的对象都会收到一个release,有可能会因此被销毁. 2-成员属性:     readonly:不指定readonly,默认合成getter和setter方法.外界毫不关心的成员,则不要设置任何属性,这样封装能增加代码的独立性和安全

IOS学习笔记 -- 多线程

多线程1.多线程的原理 1>.同一时间,CPU只能处理1条线程,只有1条线程在工作(执行) 2>.多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换) 3>.如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象如果线程非常非常多,会发生: 1>.CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源 2>.每条线程被调度执行的频次会降低(线程的执行效率降低) 2.多线程的优缺点 1>.多线程的优点 能适当提高程序的执行效率 能适当提高资源

iOS学习笔记之UITableViewController&UITableView

iOS学习笔记之UITableViewController&UITableView 写在前面 上个月末到现在一直都在忙实验室的事情,与导师讨论之后,发现目前在实验室完成的工作还不足以写成毕业论文,因此需要继续思考新的算法.这是一件挺痛苦的事情,特别是在很难找到与自己研究方向相关的文献的时候.也许网格序列水印这个课题本身的研究意义就是有待考证的.尽管如此,还是要努力的思考下去.由于实验室的原因,iOS的学习进度明显受到影响,加之整理文档本身是一件耗费时间和精力的事情,因此才这么久没有写笔记了. M

iOS学习笔记(3)— 屏幕旋转

iOS学习笔记(3)— 屏幕旋转 一.屏幕旋转机制: iOS通过加速计判断当前的设备方向和屏幕旋转.当加速计检测到方向变化的时候,屏幕旋转的流程如下: 1.设备旋转时,系统接收到旋转事件. 2.系统将旋转事件通过AppDelegate通知当前的主Window. 3.window通知它的rootViewController. 4.rootViewController判断所支持的旋转方向,完成旋转. iOS系统中屏幕旋转事件没有像触碰事件那样进行hitTest,所以只有rootViewControl