美文网首页
响应者链

响应者链

作者: 飞哥漂流记 | 来源:发表于2020-05-25 17:58 被阅读0次

    $\color{red}{响应者链的原理 ?}$

    原理 :

    首先只有继承UIResponder的的类,才能处理事件。

    当用户触摸(Touch)屏幕进行交互时,系统首先要找到响应者(Responder)。系统检测到手指触摸(Touch)操作时,将Touch 以UIEvent的方式加入UIApplication事件队列中。UIApplication从事件队列中取出最新的触摸事件进行分发传递到UIWindow进行处理。UIWindow 会通过hitTest:withEvent:方法寻找触碰点所在的视图,这个过程称之为hit-test view。

    hitTest 的顺序如下:

    点击屏幕--->UIApplication->UIWindow->Root View->···->subview

    在顶级视图(Root View)上调用pointInside:withEvent:方法判断触摸点是否在当前视图内;

    如果返回NO,那么hitTest:withEvent:返回nil;

    如果返回YES,那么它会向当前视图的所有子视图发送hitTest:withEvent:消息,所有子视图的遍历顺序是从最顶层视图一直到到最底层视图(倒叙遍历),即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕。

    如果有subview的hitTest:withEvent:返回非空对象则A返回此对象,处理结束(注意这个过程,子视图也是根据pointInside:withEvent:的返回值来确定是返回空还是当前子视图对象的。并且这个过程中如果子视图的hidden=YES、userInteractionEnabled=NO或者alpha小于0.1都会并忽略);

    如果所有subview遍历结束仍然没有返回非空对象,则hitTest:withEvent:返回self;

    系统就是这样通过hit test找到触碰到的视图(Initial View)进行响应。

    触摸事件会优先分发给附在view的手势,在这段延迟的期间,如果手势被识别,那么view的touches系列将被立刻取消,如果没有被识别,那么会继续我们所熟知的touches系列流程。

    系统判别返回的 UIView是不是 UIControl的子类,如果是的话,直接将整个触摸事件交付 UIControl实例完成

    一下是视图没有响应的几个情况:

    1.userInteractionEnabled=NO;

    2.hidden=YES;

    3.alpha=0~0.01;

    4.没有实现touchesBegan:withEvent:方法,直接执行touchesMove:withEvent:等方法;

    5.目标视图点击区域不在父视图的Frame上 (superView背景色为clear Color的时候经常会忽略这个问题)。

    触摸事件的方法:

    // 一根或者多根手指开始触摸view,系统会自动调用下面方法

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

    // 一根或者多根手指在view上移动,系统会自动调用下面方法(随着手指的移动,会持续调用该方法)

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

    // 一根或者多根手指离开view,系统会自动调用下面方法

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

    // 触摸结束前,某个系统事件(例如电话呼入)会打断触摸过程,系统会自动调用下面方法

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

    第一响应者 (The First Responder):

    简单的讲,第一响应者是一个UIWindow对象接收到一个事件后,第一个来响应的该事件的对象。

    这个第一响应者与之前讨论的触摸检测到的第一个响应的UIView并不是一个概念。第一响应者一般情况下用于处理非触摸事件(手机摇晃、耳机线控的远程空间)或非本窗口的触摸事件(键盘触摸事件),通俗点讲其实就是管别人闲事的响应者

    如果方法canBecomeFirstResponder返回YES,这个响应者对象才有资格称为第一响应者。有资格并不代表一定可以成为第一响应者,就好像符合要求并不一定能够应聘成功一样,所以还差一个聘用环节,那就是becomeFirstResponder正式成为第一响应者。

    使用场景:

    不规则图形的点击事件,或者扩大缩小点击范围,

    响应者链的事件传递过程:

    响应机制的顺序和事件传递是反着的,事件传递是从上层往下层传递,像剥洋葱一样,找到最终响应事件的view,响应机制则是从下层向上层,响应机制主要依赖的方法是:

    touchesBegin , touchesMoved, touchesEnded等方法

    响应链是通过nextResponder属性组成的一个链表。

    点击的view有 superView,nextResponder就是superView;

    如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图

    在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理

    如果window对象也不处理,则其将事件或消息传递给UIApplication对象

    如果UIApplication也不能处理该事件或消息,则将其丢弃

    响应链:由离用户最近的view向系统传递。initial view –> super view –> ….. –> view controller –> window –> Application –> AppDelegate

    基本的开发目标,不让父视图的手势识别干扰子视图UIView的点击事件响应或者说响应链的正常传递。

    一般都会是重写UIGestureRecognizerDelegate中的- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch方法。

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

        // 若为UITableViewCellContentView(即点击了tableViewCell),

        if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) { 

        // cell 不需要响应 父视图的手势,保证didselect 可以正常

            return NO; 

        } 

        //默认都需要响应

        return  YES; 

    }

    1. 简述一下响应者链?假如一个viewA 上有一个viewB,且viewB的面积大于viewA 点击viewB且不和viewA重叠的区域 是否会响应 为什么?

    答案和其他问题待更新!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    2. 有哪几种手势通知方法、写清楚方法名?

    答:

    -(void)touchesBegan:(NSSet)touchedwithEvent:(UIEvent)event;

    -(void)touchesMoved:(NSSet)touched withEvent:(UIEvent)event;

    -(void)touchesEnded:(NSSet)touchedwithEvent:(UIEvent)event;

    -(void)touchesCanceled:(NSSet)touchedwithEvent:(UIEvent)event;

    相关文章

      网友评论

          本文标题:响应者链

          本文链接:https://www.haomeiwen.com/subject/ksokahtx.html