总结自:Android内部核析

一般情况下,导致重新遍历的原因主要有三个,

一个是视图本身内部状态变化引起重绘

第二个是View树内部添加或者删除了View

第三个是View本身的大小及可见性发生变化

首先进行状态分类

1:状态有很多:如 拥有焦点(Focus) 按下(Press)等

特别要分清 selected和focused的区别

1:一个窗口中 focused的视图是唯一的 但是selected是可以多个的

2:按键消息最终会传递到focused视图中 而不是selected视图中

3:当某个视图处于pressed状态,如果将其selected设为false那么该视图的pressed会被清空

4:focused状态一般都是由按键操作引起的,pressed状态是由触摸消息引起,selected则完全是由应用程序主动调用setSelected()进行控制

一般情况下,具有selected状态的视图不会有什么界面上的变化,除非应用程序给该视图指定了selected时所使用的背景图

当视图重绘时,会根据当前不同的状态选择不同的绘制背景图,应用程序可以在res/xml目录下使用xml文件定义一组状态背景

上面说道的三种View树重新遍历的三种情况最后都直接或间接的调用到三个函数

1:invalidate()

2:requestLayout()

2:requestFocus()

这三个函数最终都会调用到ViewRoot中schueduleTraversals()

然后该方法发起一个异步消息,消息处理中调用performTraversals()开始对整个View进行重新遍历

能导致invalidate()调用的有三种情况

1:Visibility的状态改变

2:Selected的状态改变

3:Enable的状态改变

能导致requestLayout()调用的两种情况

1:Visibility的改变,由于此时显示/不显示将影响其他兄弟视图的位置.

2:应用程序直接或间接调用该函数,间接实质应用程序调用了View类的其他函数从而间接调用到requestLayout()

能导致requestFocus()的情况

上下按键

安卓怎么遍历一个MutableMap 安卓遍历view_sed

----------------------------------------

refreshDrawableList()

该函数是根据状态标识动态赋值不同的Drawable对象

setVisiblity()标识不同的状态改变View.该函数很简单

首先调用setFlags()然后调用mBGDrawable.setVisible()改变该视图背景图的显示状态

setFlags()在View类中被广泛使用,setClickable(),setEnable()等都有用到.

这个变量是使用标志位(bit)保存不同的状态

invaliddate()的作用是请求View树进行重绘,视图及其父视图在界面上市分层先后显示的

绘制过程中.首先绘制最底层的根视图,然后再绘制其包含的子视图,绘制过程一般不会对所有视图进行重绘,

而仅绘制那些"需要重绘"的视图.

对于"需要重绘":View类内部变量mPrivateFlags会有标识,如果符合就进行重绘

invalidate()的作用就是要根据所有视图中的标志位计算具体哪个区域需要重绘,将这个区域用一个矩形标识.

并最终将这个矩形存放到ViewRoot类中的mDirty变量中

之后的重绘过程将重绘所有好办在该mDirty区中的视图

比如:A覆盖在B的某个部分

1:A的alpha为0,则此时只有当A的大小或者Visiable改变时才会引起B的绘制

2:A的alpha不为0,则此时A的重绘会引起B的重绘

------------------------------------------

view树perform Traversals()的执行过程

该函数是系统内进行View树遍历工作的核心函数,内部逻辑比较复杂,

执行过程可以简单概括为:

根据之前所有设置好的状态,

1:判断是否需要重新关系计算视图大小(measure)

2:判断是否需要重新安置视图的位置(layout)

3:以及是否需要重绘(drwa)视图

安卓怎么遍历一个MutableMap 安卓遍历view_重绘_02

接着讲

measure(计算视图大小) 的过程

首先先弄清楚"视图大小"是什么,事实上,View系统中Canvas是没有边界的,当我们在自定义一个具体的View的时候

应该在onDraw(Canvas canvas)中向画布中绘制视图的界面,但是实际应用中并不会绘制一个无穷大的界面,

那么到底应该绘制一个多大的界面呢?对于不同类型的View,其绘制的大小有所不同,一般非为两种情况

1:内容型视图:比如TextView  其显示是有多少就绘制多少,所以视图的大小由内容的多少决定

2:图形视图:该视图显示的是一个图形,比如背景图等,此时该视图的大小往往会根据俯视图为该View开了一个多大的窗口而动态调整.

视图大小是无穷的.layout文件中的height和width属性设置的宽高不是指视图的大小而是指俯视图给该View设置的窗口大小,该视图可以是一个

"相对值"也可以是一个具体值

measure过程的本质就是把视图布局时候使用的"相对值"转换为具体的过程,如果是使用的具体值,那么也就完全不需要measure过程了

下一节: measure的内部设计思路