• 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,则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. 在 此例子中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. 网上的一个案例:    

          convertPoint:toView:

      转换一个点从接收者坐标系到给定的视图坐标系

      - (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view

      参数

      point

      一个在调用者坐标系中的点

      view

      一个包含了需要被转换的点的视图。如果视图是nil,那么这个方法将会转换成基于窗口的坐标。否则视图和接收者都要属于同一个UIWindow对象。

      返回值

      基于视图的坐标系转换过的点

     

  • 相关阅读:
    js将UTC时间转化为当地时区时间 用JS将指定时间转化成用户当地时区的时间
    elementUI里面,用tabs组件导致浏览器卡死的问题
    根据数组对象中的属性值删除对象
    js货币金额正则表达式
    vue elementui input不能输入的问题
    vue+elementui--$message提示框被dialog遮罩层挡住问题解决
    Oracle日期函数
    plsql查询报错:Dynamic Performamnce Tables not accessible
    Oracle rownum和rowid的区别
    Oracle通过序列实现主键自增长
  • 原文地址:https://www.cnblogs.com/LE-Quan/p/5222425.html
Copyright © 2020-2023  润新知