View树遍历的情况 -- ①

总结自: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()的情况
上下按键

----------------------------------------
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)视图



接着讲 measure(计算视图大小) 的过程
首先先弄清楚"视图大小"是什么,事实上,View系统中Canvas是没有边界的,当我们在自定义一个具体的View的时候
应该在onDraw(Canvas canvas)中向画布中绘制视图的界面,但是实际应用中并不会绘制一个无穷大的界面,
那么到底应该绘制一个多大的界面呢?对于不同类型的View,其绘制的大小有所不同,一般非为两种情况
1:内容型视图:比如TextView  其显示是有多少就绘制多少,所以视图的大小由内容的多少决定
2:图形视图:该视图显示的是一个图形,比如背景图等,此时该视图的大小往往会根据俯视图为该View开了一个多大的窗口而动态调整.


视图大小是无穷的.layout文件中的height和width属性设置的宽高不是指视图的大小而是指俯视图给该View设置的窗口大小,该视图可以是一个
"相对值"也可以是一个具体值
measure过程的本质就是把视图布局时候使用的"相对值"转换为具体的过程,如果是使用的具体值,那么也就完全不需要measure过程了


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




























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值