文章关键字 ‘Draglayer’

LauncherRootView和DragLayer的布局过程

2015年05月20日,星期三

(系列文章点这里)

话说讲解Launcher3的布局过程真是要耗费一番功夫了,因为他的过程很难理解, 一般来说我们普通应用的布局过程其实都是按照系统自带的ViewGroup来的,如果自定义了一些布局方法,开发者在考虑xml标记的布局文件的时候,还要考虑运行时的一些动态变化。

在接着往下读之前,你最好先去了解一下View的绘制流程。

在主布局launcher.xml中, 最外层是LauncherRootView。

我们发现它只是重写了一个方法, View.fitSystemWindow(rect), 那这个方法是干什么的呢?查了官方文档,还是看不懂他到底是做什么的,但是倒是会用了。如果你的View在status bar或者navigation bar之下,那么这个方法会传递进去一个参数,说明这个View的四周有多少是被status bar或者navigation bar挡住了的。这个方法的会调用父类的setInsets()方法,我们来看看父类InsettableFrameLayout。

InsettableFrameLayout继承了FrameLayout, 并且实现了父类的一些方法,总的来说,他的目的就是给子View都设定一个Margin值,防止被status bar或者navigation bar挡住。如果一个View已经是Insettable的了,那么就忽略他。在Launcher3中,Workspace, DragLayer和AppsCustomizeTabHost都实现了这个接口,那么他们自身就不会被加Margin, 而搜索栏和Hotseat都没有实现这个接口,那么说明他们在被加到父亲上得时候会被设一个Margin,最后的到得效果就是搜索栏刚好在status bar之下(gravity为top,topmargin是status bar的高度),Hotseat刚好在navigation bar的上方(gravity为bottom,bottomMargin为navigation bar的高度)。

LauncherRootView的实现已经很明了了,他的孩子只有DragLayer,DragLayer实现了Insettable接口, 所以他不会加上margin。DragLayer其实也是InsettableFrameLayout的子类, DragLayer的孩子有Workspace,Hotseat,AppsCustomizeTabHost 和 SearchDropTargetBar等等 。

DragLayer的布局过程稍微复杂一点,不过还好。DragLayer自己定义了一个LayoutParams, 在FrameLayout原有的LayoutParams基础之上,添加了几个参数,x,y和customPosition。在DragLayer中添加孩子的时候,都会自来于提供的LayoutParams来计算View的布局位置。

我们来看下DragLayer重写的onLayout方法[如果还不清楚这个方法是干啥的话,赶快搜一搜]:

2015-05-20_17-47-41

刚开始先按照FrameLayout的方式进行布局,然后,遍历所有的孩子的LayoutParams, 如果这个孩子的LayoutParams参数中含有的customPosition参数为true,那么就会使用参数里执行的x坐标和y坐标。

为什么需要这样的功能呢?比如说我们在拖拽一个图标的时候,这个图标其实是放在了DragLayer里的[drag layer,拖拽层嘛],如果给拖拽的图标分配了一个自定义位置的布局参数,那么布局完之后就可以显示在指定位置了。拖拽一个AppWidget和显示文件夹的时候也是同样道理。

理解了Launcher最外层的两个ViewGroup[LauncherRootView,DragLayer]的布局方式之后,相信你了解的更深入了一些,同学还学了自定义ViewGroup的时候如何自定义LayoutParams布局参数。再往Launcher的底层看得话就是Workspace,CellLayout了,他们会更为复杂,接下来的博文会介绍到。