zoukankan      html  css  js  c++  java
  • hitTest:withEvent:方法流程

    此方法可实现点击穿透、点击下层视图功能。

    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,则返回nil;
    3. 若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
    4. 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
    5. 如所有子视图都返回非,则方法返回自身(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的生命周期不再改变,即使触摸操作后续移动到其他视图之上。

     1 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
     2 {
     3     // 1.判断自己能否接收事件
     4     if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
     5     
     6     // 2.判断点在不在当前控件上面
     7     if (![self pointInside:point withEvent:event]) return nil;
     8     
     9     // 3.去找有没有比自己更合适的view
    10     // 从后往前遍历自己的子控件
    11     int count = self.subviews.count;
    12     
    13     for (int i = count - 1; i >= 0; i--) {
    14         // 获取子控件
    15         UIView *childView = self.subviews[i];
    16         
    17         // 转换坐标系
    18         // 把自己坐标系上的点转换成子控件做坐标系上的点
    19         CGPoint childPoint = [self convertPoint:point toView:childView];
    20         
    21         UIView *fitView = [childView hitTest:childPoint withEvent:event];
    22         // 找到最合适的view
    23         if (fitView) {
    24             return fitView;
    25         }
    26         
    27     }
    28     
    29     // 没有找到比自己更合适的view
    30     return self;
    31 }

    .定制hitTest:withEvent:方法

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

    这里有几个例子:

      1. Hacking the responder chain
      2. 在此例子中button,scrollview同为topView的子视图,但scrollview覆盖在button之上,这样在在button上的触摸操作返回的hit-test view为scrollview,button无法响应,可以修改topView的方法如下:  
        - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
      3.     UIView *result = [super hitTest:point withEvent:event];
      4.     CGPoint buttonPoint = [underButton convertPoint:point fromView:self];
      5.     if ([underButton pointInside:buttonPoint withEvent:event]) {
      6.         return underButton;
      7.     }
      8.     return result;
      9. }
        这样如果触摸点在button的范围内,返回hittestView为button,从button按钮可以响应点击事件。
  • 相关阅读:
    无线鼠标换电池了
    Jython Interactive Servlet Console YOU WILL NEVER KNOW IT EXECLLENT!!! GOOD
    Accessing Jython from Java Without Using jythonc
    jython podcast cool isnt't it?
    Python里pycurl使用记录
    Creating an Interactive JRuby Console for the Eclipse Environment
    微软为AJAX和jQuery类库提供CDN服务
    Download A File Using Cygwin and cURL
    What is JMRI?这个是做什么用的,我真没看懂但看着又很强大
    用curl 发送指定的大cookie的http/https request
  • 原文地址:https://www.cnblogs.com/H7N9/p/4943826.html
Copyright © 2011-2022 走看看