hitTest:withEvent:调用过程

转载 2013年12月05日 23:34:24

一. hitTest:withEvent:调用过程

iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,UIApplication会从事件队列中取出触摸事件并传递给key window(当前接收用户事件的窗口)处理,window对象首先会使用hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,称之为hit-test view。

window对象会在首先在view hierarchy的顶级view上调用hitTest:withEvent:,此方法会在视图层级结构中的每个视图上调用pointInside:withEvent:,如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是hit-test view。

hitTest:withEvent:方法的处理流程如下:

  1. 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
  2. 若返回NO,则hitTest:withEvent:返回nil;
  3. 若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
  4. 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
  5. 如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。

hitTest:withEvent:方法忽略隐藏(hidden=YES)的视图,禁止用户操作(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。如果一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常情况下对子视图在父视图之外区域的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种情况。

对于每个触摸操作都会有一个UITouch对象,UITouch对象用来表示一个触摸操作,即一个手指在屏幕上按下、移动、离开的整个过程。UITouch对象在触摸操作的过程中在不断变化,所以在使用UITouch对象时,不能直接retain,而需要使用其他手段存储UITouch的内部信息。UITouch对象有一个view属性,表示此触摸操作初始发生所在的视图,即上面检测到的hit-test view,此属性在UITouch的生命周期不再改变,即使触摸操作后续移动到其他视图之上。

二.定制hitTest:withEvent:方法

如果父视图需要对对哪个子视图可以响应触摸事件做特殊控制,则可以重写hitTest:withEvent:pointInside:withEvent:方法。

这里有几个例子:

  1. hitTest Hacking the responder chain
    在此例子中button,scrollview同为topView的子视图,但scrollview覆盖在button之上,这样在在button上的触摸操作返回的hit-test view为scrollview,button无法响应,可以修改topView的hitTest:withEvent:方法如下:

     

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        UIView *result = [super hitTest:point withEvent:event];
        CGPoint buttonPoint = [underButton convertPoint:point fromView:self];
        if ([underButton pointInside:buttonPoint withEvent:event]) {
            return underButton;
        }
        return result;
    }

    这样如果触摸点在button的范围内,返回hittestView为button,从button按钮可以响应点击事件。

  2. Paging-enabled UIScrollView with Previews
    BSPreviewScrollView 
    关于这两个例子,可以看之前文章的说明,见Paging-enabled UIScrollView

防止一个方法调用两次

/** 用来防止两次弹出 alertVIew */ static int tostFlag = 0; -(UIView *)hitTest:(CGPoint)point withEvent:(...
  • qq_27074387
  • qq_27074387
  • 2016年12月09日 20:55
  • 721

hitTest:withEvent:方法流程

此方法可实现点击穿透、点击下层视图功能。   一. hitTest:withEvent:调用过程 iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application...
  • jiajiayouba
  • jiajiayouba
  • 2014年04月11日 15:03
  • 22030

iOS 【UIKit-事件产生与传送 练习(重写hitTest和pointInside方法)】

练习要求: 在下图中点击到绿色Button区域,Button响应(包括YellowView覆盖的绿色Button部分也是由绿色Button来响应)。点击YellowView部分(除覆盖绿色Butto...
  • Felicity294250051
  • Felicity294250051
  • 2016年01月10日 10:55
  • 1546

[IOS]hitTest的作用与用法【转】

hitTest的作用:当在一个view上添加一个屏蔽罩,但又不影响对下面view的操作,也就是可以透过屏蔽罩对下面的view进行操作,这个函数就很好用了。   hitTest的用法:将下面的...
  • smking
  • smking
  • 2013年08月06日 14:38
  • 13925

iOS开发-事件传递与响应者链中的hitTest方法和pointInside方法

事件传递与响应者链是iOS开发中的重点基础知识,也是容易混淆的知识点。
  • Cehae
  • Cehae
  • 2016年10月15日 12:56
  • 1113

树形视图和列表视图中的HitTest

1、引言       HitTest为命中测试的意思。在使用MFC编写程序的时候,在树形视图以及列表视图中通常会涉及到需要获得鼠标当前位置所对应的元素。这种通过光标坐标位置来获得相应元素项的操作我们...
  • zcube
  • zcube
  • 2014年04月02日 21:04
  • 4355

hitTest:方法练习 - 点击事件穿透

2.把 storyboard里的button连线(我们发现不能连线),这时我们选择 从代码里连线到storyboard上 3.#import "YellowView.h" @interfa...
  • github_26672553
  • github_26672553
  • 2016年03月04日 20:52
  • 502

iOS事件的分发机制和响应者链(Swift)

当我们在设计自己的APP时,可能会想动态的响应事件.例如:屏幕上许多对象都能够发生触摸,我们必须决定哪一个对象来响应给定的事件并且知道对象是如何接受事件的。当用户事件产生的时候,UIKit会创建一个事...
  • longshihua
  • longshihua
  • 2016年07月19日 10:48
  • 2585

UIView的hitTest:方法和pointInside:方法的实现

处理原理如下: ? 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中 ? UIApplication会从事件队列中取出最前面的事件...
  • YUXIANG19876021
  • YUXIANG19876021
  • 2015年12月07日 14:10
  • 383

IOS图层Layer学习笔记(三)—— CALayer(下)

CALayer方法
  • xiepanqi
  • xiepanqi
  • 2015年11月24日 19:28
  • 711
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hitTest:withEvent:调用过程
举报原因:
原因补充:

(最多只允许输入30个字)