View更新绘制过程


view是以树形结构组织在一起,如下图所示:


这个图没有把RootView画出来,rootView只有一个孩子DecorVeiw,此DecorVeiw


android4.0/frameworks/base/core/res/res/layout/screen_title.xml这个文件中inflate出来的,


PhoneWindow.javagenerateLayout方法中的关键代码片段


Viewin = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT))
ViewGroupcontentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);


contentParent,是我们在ActivitysetContentView时其实就是将我们的布局挂在这个


contentParent上了,而contentParent又是挂靠在decor上的孩子view,所以一个activityview布局就是一棵树,


所以绘制的时候也是按照树形结构,通过遍历来进行绘制。VeiwRoot中的draw函数准备好Canvas之后,


就会调用mVeiw.draw(Canvas),mVeiw就是调用ViewRoot.setView时设置的DecorViewDecorView本质


是一个FrameLayout,也就是说踏实一个Veiw,然后我们就可以来看看View.java中的draw函数都做了些什么事情:


/*
* Draw traversal performs several drawing steps which must beexecuted
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare forfading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/


.绘制背景


.如果有需要,保存画布,为淡入淡出做准备。


.绘制view本身的内容,通过调用onDraw(canvas)方法,次方法中通过Canvas,画各种图形,直线,圆,图片等。


.绘制挂靠在自己上面的孩子Veiw,通过dispatchDraw(canvas)方法来实现,在view中这个方法是一个空函数,


这也好理解view下面不会挂靠孩子View,所以用不着这个方法。而VeiwGroup实现了此方法,因为VeiwGroup


是可以挂靠孩子Veiw的。VeiwGroup.javadispatchDraw(canvas)方法中做的事情:


首先会判断有没有layoutAnimation,如果有的话,会将layoutAnimation通过LayoutAnimationContraller将


layoutAnimation与每一个孩子View进行关联。


然后轮询调用drawChild() 绘制孩子View


drawChild()---->child.draw(canvas,this,drawingTime),这样的调用过程保证每一个孩子viewdraw方法都被调


用,通过递归调用,就保证整棵树上的viewdraw方法都被调用,从而所有的view都能被绘制出来。


child.draw(canvas,this,drawingTime)方法中会调用

.

..

more= drawAnimation(parent,drawingTime,a,scalingRequired);

..

.


drawAnimation中通知父亲View绘制自己,形成动画效果


在调用每个子Viewdraw函数之前,需要绘制的View的绘制位置是在Canvas通过translate函数调用来进行切换


的,窗口中的所有View是共用一个Canvas对象。整棵树用的都是同一个Canvas


Canvas是在什么时候切换坐标系的?

其实就是在这个方法里面进行转换的,什么时候呢?在view要更新时,当父亲Veiw调用


dispatchDraw(canvas)-->drawChild()---->child.draw(canvas,this,drawingTime);


然后child.draw(canvas,this,drawingTime)方法中回去变换canvas的坐标系,当坐标系变换好了之后,就会调用


当前child的draw(canvas)方法,此时的参数canvas已经是转换了坐标的。继续进入draw(canvas)中的六个步骤,依


次递归。如果veiw没有孩子就不会再调用dispatchDraw(canvas),直接将自己的内容画出来就结束了,如果还有孩


子Veiw,则还是会调用到dispatchDraw(canvas),继续递归。


boolean draw(Canvas canvas, ViewGroup parent, long drawingTime)



.如果有需要,绘制淡入淡出相关的内容并恢复保存的画布


.绘制修饰内容(例如滚动条)


孩子view要更新都是通过invalidate()方法来通知父亲view来更新自己。这个过程一直上溯到ViewRoot,ViewRoot


收到这个通知后,就会调用他的draw方法。然后通过递归调用完成绘制。VeiwonDrawCanvascanvas)方法中


都会有一canvas,这个canvas实就是在ViewRootdraw方法中创建的那个canvas,所以整个View树公用的是


同一Canvas例,Canvas是有坐标系的,并且这个坐标系是可以变换的,平移,旋转,缩放,错切,对称等变


换。默认的坐标系是屏幕的左上角为(0,0),横向为x轴,竖向为y轴。Canvas的一个重要属性就是定义和view


对应的坐标系,你会发现,每个view中拿到的canvas的坐标系都是以view的左顶点为原点的,这是通过canvas


平移变换实现的。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值