您的位置:首页 > 移动开发 > Android开发

View的绘制过程分析

2016-05-24 20:43 489 查看
写在前面:

最近在学习《Android开发艺术探索》关于View的工作原理的内容,虽然讲解的很细致,但总觉得仅仅看一遍还是难以对View的整体绘制过程有较为明晰的认识。接下来,我根据简单的代码,重点观察分析View的measure– layout – draw 绘制过程。

一、xml文件

其中,RevealLayout本质上就是LinearLayout。MyButton本质上就是Button。这里是为了方便观察绘制过程,对相关方法添加了打印信息。

<com.ryg.chapter_4.ui.RevealLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="12dp"
tools:context="${relativePackage}.${activityClass}" >

<com.ryg.chapter_4.ui.MyButton
android:id="@+id/button1"
style="@style/AppTheme.Button.Green"
android:onClick="onButtonClick"
android:text="View Test" />

</com.ryg.chapter_4.ui.RevealLayout>


二、 运行结果

如下图,就只显示一个简单的Button,重点是对其绘制过程的观察。



三、View绘制过程方法调用

控件构造器:RevealLayout()、MyButton() → RevealLayout().onMeasure→ RevealLayout().measureChildWithMargins→ MyButton.onMeasure → RevealLayout().onLayout → MyButton.layout → MyButton.onLayout → RevealLayout().draw → RevealLayout().onDraw → RevealLayout().dispatchDraw → MyButton.draw → MyButton.onDraw



四、View绘制过程分析

1) View的绘制过程从何处开始呢?

关于这个问题,可参考http://www.cnblogs.com/jerehedu/p/4679534.html。Acitvity启动过程中,追溯其源码,可得出下图所示的调用过程:



Activity在启动过程中会调用主线程ActivityThread的handleResumeActivity方法,此方法会将DecorView和WindowManagerImpl对象关联起来。最终,ActivityThread中生成的DecorView经过WindowManagerImpl、WindowManagerGlobal,最终调用了ViewRootImpl中的setView方法,将DecorView设置赋值给了ViewRootImpl中的mView属性。在ViewRootImpl中调用的performTraversals方法将会开启View的整个绘制过程。

private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
……
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
……
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
……
performDraw();
……
}


2)View绘制过程深入



measure过程:

1.View的measure方法为final类型,不能被重写。在measure方法中会调用onMeasure方法,因而一般重写onMeasure方法实现自定义View。

2.View的onMeasure方法本身设定View的测量后大小为android:minWidth属性所设置的值,此属性默认为0。如果为View指定了背景,则View的测量后大小为背景图片的原始尺寸。另外,直接继承View的控件需要重写onMeasure方法设置wrap_content时的自身大小,否则其效果等同于match_parent.

3.对于ViewGroup实例,比如LinearLayout、RelativeLayout等,不仅要根据自己的布局特性重写onMeasure方法还要实现对子元素进行measure的方法。

4.view的大小取决于:父容器的MeasureSpec、父容器的padding以及view本身的LayoutParams。

5.measure过程可能要进行多次才能确定最终的测量宽/高,因而在measure过程中去获取view的宽/高可能会不准建议在onLayout方法中获取。

6.view的measure过程和Activity的生命周期方法并不同步。不能保证某一个生命周期阶段measure确定完成。

layout过程:

1.layout方法确定View本身的位置,onLayout方法确定所有子元素的位置。

2.onLayout的具体实现和具体布局有关,所以View和ViewGroup都只提供了空方法,需要子类重写。

3.对ViewGroup实例,在onLayout方法中会遍历子元素调用其layout方法。

4.在onLayout方法中需要对LayoutParameters.margin进行处理。

draw过程:

View.draw()分为以下几步:

(1)background.draw():绘制背景;

(2)onDraw():绘制自己;

(3)dispatchDraw():绘制子元素;

(4)onDrawScrollbars:绘制装饰。

1.自定义View一般会重写onDraw方法,需要处理padding。

2.dispatchDraw方法实现draw事件的一层层传递。

3.自定义View时序注意View中的setWillNotDraw方法。此方法为优化标志位。

setWillNotDraw(true)表示view不需要绘制任何内容,系统会进行响应优化。

默认情况下,View未启动此标志位,ViewGroup启动此标志位。

当自定义控件继承自ViewGroup时且需要绘制内容时需显式关闭此优化标记位。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android View 绘制过程