Onelong

分享知识,与你一起进步......
RSS icon Home icon
  • iOS和Android事件派发

    post by onelong / 2016-11-20 15:08 Sunday [工作]
    1、点击一下iOS设备的屏幕,硬件产生一个电平变化信号操作系统内核驱动捕捉,通过Event Queue传递到用户态,UIKit就会生成一个事件对象UIEvent
    2、UIKit把这个Event分发给当前活动的app。
    3、当前活动的app有事件之后,UIApplication 单例就会从事件队列中去取最新的事件,然后分发给能够处理该事件的对象。
    4、UIApplication 获取到Event之后,Application就纠结于到底要把这个事件传递给谁,这时候就要依靠HitTest来决定了。
    5、iOS中,hit-Testing的作用就是找出这个触摸点下面的View是什么,HitTest会检测这个点击的点是不是发生在这个View上,如果是的话,就会去遍历这个View的subviews,直到找到最小的能够处理事件的view,如果整了一圈没找到能够处理的view,则返回自身。
    事件传递链如下图:
     点击查看原图
    例如UI显示列表如下:
    <RootView>
        <ViewA>
            
    <ViewC></ViewC>
            <ViewD></ViewD>
        </ViewA>
        
    <ViewB></ViewB>
    </RootView> 
    点击ViewC 打印日志如下:

    RootView hitTest before
    RootView pointInside before
    RootView pointInside return
    VIewB hitTest before
    VIewB pointInside before
    VIewB pointInside return false
    VIewB hitTest return
    ViewA hitTest before
    ViewA pointInside before
    ViewA pointInside return true
    ViewD hitTest before
    ViewD pointInside before
    ViewD pointInside return false
    ViewD hitTest return
    ViewC hitTest before
    ViewC pointInside before
    ViewC pointInside return true
    ViewC hitTest return
    ViewA hitTest return

    RootView hitTest return
    RootView hitTest before
    RootView pointInside before
    RootView pointInside return
    VIewB hitTest before
    VIewB pointInside before
    VIewB pointInside return false
    VIewB hitTest return
    ViewA hitTest before
    ViewA pointInside before
    ViewA pointInside return true
    ViewD hitTest before
    ViewD pointInside before
    ViewD pointInside return false
    ViewD hitTest return

    ViewC hitTest before
    ViewC pointInside before
    ViewC pointInside return true
    ViewC hitTest return
    ViewA hitTest return
    RootView hitTest return

    ViewC touchesBegan before
    ViewA touchesBegan before
    RootView touchesBegan before
    ViewController touchesBegan before
    ViewController touchesBegan return
    RootView touchesBegan return
    ViewA touchesBegan return
    ViewC touchesBegan return

    发现很奇怪的现象是hitTest调用了两次,传递链和响应链是相反的,这是软件设计上技巧。只有遇到最小View的pointInside return true时,完成了响应对象的查找。传递时从RootView开始的而响应却是ViewC开始的到这里,iOS的事件响应就说完了。

    1、点击屏幕,首先事件的传递从Activity的dispatchTouchEvent()方法开始。
    2、关于Android事件分发机制,相关方法的方法有三个:onTouchEvent(),dispatchTouchEvent(),还有onInterceptTouchEvent(),而相关的类有Activity,View,ViewGroup。
    3、事件的分发顺序为dispatchTouchEvent --- onInterceptTouchEvent --- onTouchEvent
    4、Android事件分发机制,有一个向下分发过程,该过程主要调用dispatchTouchEvent,还有一个向上返回过程,主要依靠onTouchEvent方法,
    5、Android事件从父视图分发到子视图,如果事件被拦截,则事件不会继续向下分发,而被当前视图消耗。此时上述的向下分发过程提前结束
    6、没有被消耗的事件,从父视图逐级分发到子视图,最后又回到Activity,被Activity中的onTouchEvent()消耗。此时上述的向上返回过程提前结束

    Android也类似,上图
     
    点击查看原图
     
    具体的案例我就说了,请看 
    http://www.jianshu.com/p/7daf0feb6c2d
    android的onIntercepTouchEvent和iOS的pointInside是相同的意思,dispatchTouchEvent和hitTest也相似。不同的是iOS是派发完了才响应Touch事件。而Android的是派发过程同步处理OnTouchListener.onTouch(this, event)的。

    事件分发机制,可以分为两个过程,一个是向下分发过程,一个是向上返回过程,其中向下分发是靠dispatchTouchEvent 方法,从Activity的dispatchTouchEvent 直到目标视图的dispatchTouchEvent ,然后进入目标视图的onTouchEvent,向上返回则是靠onTouchEvent,从目标视图的onTouchEvent直到Activity的onTouchEvent。
    而在向下分发的过程可能会提前结束,这受onInterceptTouchEvent影响,也可能是ViewGroup没有子视图了,在两个因素都可以使该过程提前结束,从而提前进入向上返回的过程。向上返回过程也可能提前结束,如果事件在onTouchEvent中返回true,即事件被消费,那么事件不会继续向上传递,该过程提前结束。
     

    http://suenblog.duapp.com/blog/100031/iOS事件分发机制(一)%20hit-Testing
    http://www.jianshu.com/p/e08b80856e1a 

    引用地址:
     

    我要评论