iOS事件

2018-06-14  本文已影响16人  NapoleonY

概述

iOS中事件有触摸事件、加速计事件、远程控制事件,下面以触摸事件为例研究下iOS事件相关的内容


iOS事件分类

UIResponsder

iOS中继承了UIResponsder的对象才能够响应事件,如UIViewControllerUIViewUIApplication
UIResponsder能够响应事件的原因是:提供了几个方法来处理事件

//触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;//手指触摸事件开始时调用该方法
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;//手指在屏幕上移动时调用该方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

//加速计事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

//远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

备注:

  1. 当多个手指同时触摸屏幕时,只会调用一次touchesBegan:withEvent:方法,touches中包含多个UITouch对象,分别对应着触摸屏幕的手指
  2. 如果是UIViewController的事件,在UIViewController中重写上面用到的方法即可;如果是UIView的事件,需要在子类中重写上面用到的方法

实例:触摸屏幕,移动屏幕上的某个UIButton

UIView的子类中重写touchesMoved: withEvent:方法

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];//当前点的位置
    CGPoint previousPoint = [touch previousLocationInView:self];//上一个点的位置
    CGFloat xPoint = point.x - previousPoint.x;
    CGFloat yPoint = point.y - previousPoint.y;
    NSLog(@"point:%@;previousPoint:%@;xPoint:%f;yPoint:%f",NSStringFromCGPoint(point), NSStringFromCGPoint(previousPoint), xPoint, yPoint);
    CGPoint centerPoint = self.btn.center;
    centerPoint = CGPointMake(centerPoint.x + xPoint, centerPoint.y + yPoint);
    self.btn.center = centerPoint;
}

iOS 事件处理过程

iOS事件分为事件传递、事件响应两个过程。

事件的产生

发生触摸事件后,系统会将事件加入到由UIApplication管理的队列(先进先出FIFO),然后将队列最前面的事件分发下去:UIApplication->keyWindow->视图层次结构,找到合适的视图控件后,就会调用对应控件的事件方法(touchesBegan: withEvent:等)来处理对应的事件。

事件的传递

触摸事件的传递是从父控件传递到子控件

  1. 不允许交互userInteractionEnabled = NO
  2. 隐藏的控件不能接收事件
  3. 透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。

事件传递实例

注意:如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件

事件传递实例

查找符合条件的控件原理

主要是通过以下两个控件实现查找

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;//返回nil,表明当前view以及子view没有能够响应事件的;如果不为nil,则表明当前view中有能响应事件的
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;//返回YES,表明触摸点在当前view中

通过调用hitTest:withEvent:可以判断是否有能够响应事件的控件,具体步骤为:
产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回合适的view->[子控件 hitTest:withEvent:]->返回合适的view
不过子控件是否能够响应事件,父控件都会把事件传递给子控件,如果子控件不能响应事件,则父控件响应事件

实例:view中的button响应事件

参考iOS超出父视图后点击事件不响应,文中想要view中的button响应点击事件,因此重写了hitTest:withEvent:方法

响应者链

在iOS程序中无论是最后面的UIWindow还是最前面的某个按钮,它们的摆放是有前后关系的,一个控件可以放到另一个控件上面或下面,那么用户点击某个控件时是触发上面的控件还是下面的控件呢,这种先后关系构成一个链条就叫“响应者链”。

事件响应过程

总结

  1. 触摸屏幕产生触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中
  2. UIApplication会从事件队列中取出最前面的事件,把事件传递给keyWindow
  3. keyWindow会在视图层次结构中找到一个最合适的视图来处理触摸事件
  4. 最合适的view会调用自己的touches方法处理事件,如果不能处理事件,就将事件沿着响应者链向上抛

参考

  1. iOS事件传递->处理->响应
  2. iOS超出父视图后点击事件不响应
上一篇下一篇

猜你喜欢

热点阅读