Launcher UI结构与事件传递处理分析

来源:互联网 发布:轻松学英语软件 编辑:程序博客网 时间:2024/05/17 06:59

上一章分析了View事件传递过程,这章结合上章的知识来分析事件在Launcher中的传递和处理过程。

首先看看Launcher的View树形结构:

这里写图片描述

1.相关元素介绍:

  • DragLayer:View根元素,处理桌面元素的拖拽。
    WorkSpace:继承PagedView,处理屏幕滑动。
    CellLayout:ViewGroup,处理元素的大部分处理逻辑,如获取并封装触摸位置的cellInfo对象。
    ShortCutAndWidgetContainer:ViewGroup,从CellLayout抽离出来专门处理最内层元素布局,如Application、FolderIcon。
    BubbleTextView:TextView,对Application的专门处理,text/Icon布局显示。
    Folder:LinearLayout,文件夹内的元素的展示以及相关的操作(点击/长按)。

对于UI的分析我们可以依赖hierarchyviewer.bat(sdk\tools\hierarchyviewer.bat
)工具,可以看出UI的结构以及每个View测量、绘制的时间。

2.Launcher的初始化过程简单来讲包括下面几个:

  • 依据屏幕大小初始化每屏可放置的元素个数。

  • 初始化各个元素大小(icon,folder,padding等)以及view的宽/高(可以理解为Measure过程)。

  • 初始化view(findViewById)并将相关的依赖注入至对应的View元素对象,比如mWorkspace.setup(dragController)。

  • 给每个View布局位置(Layout)。

3.初步了解完Launcher的UI结构后我们来分析下事件传递:

  • 所有的事件可以理解为从Activity分发至window上的底层ViewGroup,然后再往上层分发,假设传至顶层时还未被拦截与消耗,那么则会一层层返回至事件分发的activity,并处理相关事件(onTouch、click、longClick等)。

  • Click的触发是在系统捕捉到ACTION_UP后发生并由performClick()执行的,performClick里会调用先前注册的监听器的onClick()方法,LongClick的触发则是从ACTION_DOWN开始,由postCheckForLongClick()方法完成,在ACTION_DOWN事件被捕捉后,系统会开始触发一个postDelayed操作,delay的时间在4.4上为300ms,300ms后会触发CheckForLongPress线程的执行。

Launcher中桌面元素注册click/longClick事件至Launcher.java中统一处理。

  • 点击:
    Launcher设计上针对点击事件不予拦截(不符合拦截的case),所以一定会最终交给目标view自己处理相应的点击操作(Launcher接管处理)。

  • 长按:
    判断是否拦截 (ACTION_DOWN):
    A)首先会在DragLayer的onInterceptTouchEvent里面处理:
    1)如果Folder正在编辑名字则拦截,Folder退出编辑(名字生效)
    2)Folder打开时,如果触发事件的位置不在Folder上则拦截,并关闭Folder

    B)由于DragLayer是通过DragControl来控制元素的拖动,所以也会通过DragControl的onInterceptTouchEvent来进一步的判断是否需要拦截:
    如果是mDragging状态则拦截

    C)DragLayer处理完后便交给WorkSpace处理,WorkSpace交由父类PagedView处理
    1)屏幕正在滑动时拦截
    2)屏幕正在翻页(前一页、后一页)时拦截

    D)WorkSpace处理完后便交给CellLayout处理,CellLayout会判断WorkSpace相关状态

    1)WorkSpace滑动过度状态未完成时拦截

    2)WorkSpace处于非小视图但是当前触发的view并不是在当前显示的page上面

注意如果CellLayout未拦截的话会将当前点击的位置与ShortcutAndWidgetContainer里面所有的元素遍历,重新生成cellInfo对象,并设置为此View的Tag。

长按时由于不符合拦截条件,所以传递至Launcher.java的onLongClick来处理(会进入拖拽状态)。

  • ACTION_MOVE:
    A)DragLayer并没有对MOVE拦截而是交给DragControl处理,如果处于Drogging状态则拦截。

    B)由于DragControl拦截了(处于Draging状态),所以MOVE事件交给DragControl的TouchEvent处理。

  • ACTION_UP:
    DragLayer同样交给DragControl处理,当然还是Drogging状态时拦截,否则会停止拖动,并让事件传递至子view处理

    这里如果UP事件触发时在删除控件的区域的话会删除此view,否则的话则移动至相应的位置或者是合并至文件夹。

滑动拦截与处理

  • 通过前面的介绍我们知道onLongClick事件是需要时间才能构成的,那么当ACTION_MOVE在期间出现的话则不会触发onLongClick,所以当ACTION_MOVE触发时,DragLayer不会拦截(不是longClick状态,isDraging为false),那么会传递至PagedView处理,在其onInterceptTouchEvent中的ACTION_MOVE会判断用户点击的x、y坐标是否在我们定义的区域内(我们这里定义了一个矩形区域),如果是的话则更改mTouchState = TOUCH_STATE_SCROLLING,并拦截,然后在onTouchEvent的ACTION_MOVE里面处理滑动。

下面来看看时序图:

  • 拖动事件拦截:

这里写图片描述

  • 拖动事件处理:

这里写图片描述

  • 滑动事件处理:

这里写图片描述

关于Launcher的事件传递分析就到这,基本上都是思路的分析,没有将相关代码贴出来,后续会针对Launcher源码专门写一系列分析的文章,那会从代码层开始分析。

1 0
原创粉丝点击