首页 > 技术文章 > 屏幕事件穿透和拦截分析

andbut 2016-05-06 09:09 原文

事件穿透和拦截机制同样并不是deviceone平台独有的,这个机制几乎是所有和UI相关的技术都共有,了解一下非常有必要。我们会以一个简单的例子来描述事件处理机制运行的过程。

屏幕事件处理机制

我们先假定是手机屏幕显示一个UI,里面包括了4个View,这些View都是树状结构,父View下包含一个或多个子View,其中最上层的View和屏幕大小是一致的,参考下图:


我们可以看到view1有一个子节点view2,view2包含2个子节点view3和view4.

假如我们点击屏幕一个位置,会产生一个事件event对象,整个流程都是这个对象在流转,如下图:

接下来的流程是:

  1. 整个屏幕接受到点击事件后,view1先处理,注意是view1哦。我们命名这个事件叫event1,这个事件包含了坐标值,这个时候假设这个点击的位置的坐标是(x0,y0),这里我们的坐标都是相对整个屏幕。
  2. view1接受到event1后先判断自己有没有子节点,发现有一个子节点view2,先问view2:“点击事件是你的区域内吗?”
  3. view2是一个矩形,它会先判断(x0,y0)是否在自己的区域里,如果是,继续判断自己有没有子节点,发现有2个子节点,先问view3,再问view4同样的问题:“点击事件是在你的区域内吗?”
  4. view4告诉它的父节点view2,“点击是在我的区域里了”,view2会继续问view4,“那你处理这个event1吗?”
  5. view4如果处理,那么event1的生命周期就到此结束了。(这是通常情况,有特殊情况,它可以处理完event1,又手动把事件传递给别的view
  6. view4如果不处理,那么event1又返回到父亲节点view2,同样的逻辑,view2处理或者不处理返回给它的父节点view1

总之,事件处理的机制是从根节点逐步到最末端的子节点,然后又返回回来一级级向父节点传递。

事件穿透和拦截

有了上面的机制基础,我们就可以理解一下touch事件的处理方式了。比如下面的四种点击处理,在不同的事件订阅情况下有不同的结果。如下:

1. 四个view都订阅了事件
view1.on("touch",function(){
deviceone.print("view1 touch")
})
view2.on("touch",function(){
deviceone.print("view2 touch")
})
view3.on("touch",function(){
deviceone.print("view3 touch")
})
view4.on("touch",function(){
deviceone.print("view4 touch")
})

  

结果就是:

  1. 点击1 会打印 "view1 touch"
  2. 点击2 会打印 "view2 touch"
  3. 点击3 会打印 "view3 touch"
  4. 点击4 会打印 "view4 touch"
2. 四个view都订阅了事件,但是view4的订阅没有任何代码执行。会导致事件拦截
view1.on("touch",function(){
deviceone.print("view1 touch")
})
view2.on("touch",function(){
deviceone.print("view2 touch")
})
view3.on("touch",function(){
deviceone.print("view3 touch")
})
view4.on("touch",function(){
//do nothing
})

  

结果就是:

  1. 点击1 会打印 "view1 touch"
  2. 点击2 会打印 "view2 touch"
  3. 点击3 会打印 "view3 touch"
  4. 点击4 什么都不会打印,事件被view4拦截了
3. 只有三个view订阅了事件,view4没有订阅。会导致事件穿透。
view1.on("touch",function(){
deviceone.print("view1 touch")
})
view2.on("touch",function(){
deviceone.print("view2 touch")
})
view3.on("touch",function(){
deviceone.print("view3 touch")
})

  

结果就是:

  1. 点击1 会打印 "view1 touch"
  2. 点击2 会打印 "view2 touch"
  3. 点击3 会打印 "view3 touch"
  4. 点击4 会打印 "view2 touch"view4上的点击穿透view4到达view2
4. 只有view1订阅了事件,其它都没有订阅。会导致事件一直穿透到最根节点。
view1.on("touch",function(){
deviceone.print("view1 touch")
})

  

结果就是:
    1. 点击1 会打印 "view1 touch"
    2. 点击2 会打印 "view1 touch"
    3. 点击3 会打印 "view1 touch"
    4. 点击4 会打印 "view1 touch"

推荐阅读