美文网首页
UIView响应链

UIView响应链

作者: kuperxu | 来源:发表于2016-07-24 23:47 被阅读329次

    核心方法

    • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
      参数:
      point:一个点特指一个接收者的本地坐标系中的位置(bounds)
      event:事件保证了方法的调用。如果你调用这个方法从你事件处理的外部代码,可能得到nil

    该方法层次遍历视图通过调用pointInside:withEvent:方法对每个子视图来决定那个子视图应该接受触摸事件。如果pointInside:withEvent:放回YES,然后子视图的层次结构同样遍历直到找到包含点击点的视图。如果视图不包含点,他的视图分支就被忽略。你极少需要调用这个方法,但是你可能重写他来隐藏子类的触摸事件。

    注 意:不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,事件都会先传递给这个控件,随后再调用hitTest:withEvent:方法(这两个前提)

    响应链实现机制(要拦截一个事件,你把这个监听会设置哪里)
    1、默认的hit-testing顺序是按照UIView中Subviews的逆顺序

    2、如果View的同级别Subview中有重叠的部分,则优先检查顶部的Subview,如果顶部的Subview返回nil, 再检查底部的Subview

    3、Hit-Test也是比较聪明的,检测过程中有这么一点,就是说如果点击没有发生在某View中,那么该事件就不可能发生在View的Subview中,所以检测过程中发现该事件不在ViewB内,也直接就不会检测在不在ViewF内。也就是说,如果你的Subview设置了clipsToBounds=NO,实际显示区域可能超出了superView的frame,你点击超出的部分,是不会处理你的事件的,就是这么任性!(如果是mask呢)

    事件产生

    1.发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中为什么是队列而不是栈?因为队列的特定是先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。 2.UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。 3.主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。 4.找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

    上面所讲述的东西都是响应链的建立过程但是,响应者是如何相应的呢?

    这个还是很有讲究的,苹果有一个类叫做UIResponser这里面有一系列touch方法。当你的view是响应者的时候他的响应方法就这这些touch系类的方法。如果不重写这方法的他是不会响应的。UIViewController类是通过viewwillapper这一系类方法进行相应。UIButton则是通过addtarget方法。但是说到根本都是实现了方法。另外需要注意的,我们经常在Controller里面写touch方法,其实你如果是在viewController.m文件中重写touchBegan:withEvent:方法,相当于处理的是viewController的触摸事件,因为viewController也是继承自UIResponder,所以会给人一种错觉。所以,还是那句话,想处理UIView的触摸事件,必须自定义UIView子类继承自UIView。(如果定义了手势会在调用了began之后调用手势)

    产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回更合适的view->[子控件 hitTest:withEvent:]->返回最合适的view

    UIView不能接收触摸事件的三种情况:
    不允许交互:userInteractionEnabled = NO
    隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
    透明度:如果设置一个控件的透明度
    这可以说是断链(响应链)的三种方法,而上面对象没实现自己的响应方法不会断链。(注:断链会使所有子响应都不会接受响应即使实现了响应方法)

    推荐文章:伯乐在线

    相关文章

      网友评论

          本文标题:UIView响应链

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