View绘制流程
2020-06-22 本文已影响0人
wildeyess
view的绘制流程是一个比较复杂且难懂的知识,根据这篇博客自己做一些总结
一文彻底搞懂Android View的绘制流程
1. Window,DecorView 与 ViewRootImp 的三角恋关系
- window 顶级窗口外观和行为策略的抽象基类。此类的实例应用作添加到窗口管理器的顶级视图。它提供标准的UI策略,例如背景,标题区域,默认键处理等。
该抽象类的唯一现有实现是android.view.PhoneWindow,您需要在需要Window时实例化该实例。作用(DecorView的显示是需要window来呈现)。代码体现:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....
// 创建Activity,会调用Activity的onCreate方法
// 从而完成DecorView的创建
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.tolen, false, r.isForward, !r.activity..mFinished && !r.startsNotResumed);
}
}
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 调用Activity的onResume方法
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
...
if (r.window == null &&& !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
// 得到DecorView
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
// 得到了WindowManager,WindowManager是一个接口
// 并且继承了接口ViewManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
// WindowManager的实现类是WindowManagerImpl,
// 所以实际调用的是WindowManagerImpl的addView方法
wm.addView(decor, l);
}
}
}
}
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
...
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
...
}
- DecorView setContentView 里面的根布局layout (就是个帧布局layout)
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
}
- ViewRootlml DecorView 的measure,layout,draw(开始)流程 都由它控制。有viewrootlml调用decorview.measure,decroview.layout,decroview.draw,开始view整体的绘制流程。代码体现
private void performTraversals() {
...
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
...
//执行测量流程
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
//执行布局流程
performLayout(lp, desiredWindowWidth, desiredWindowHeight);
...
//执行绘制流程
performDraw();
}
2. MeasureSpec
measurespec就是测量view的一个数据封装类。它包含了两个信息
- SpecMode (测量模式) 三个值 EXACTLY(表示一个准备可知的值) ,AT_MOST(表示最大不能大于父亲view的长宽),UNSPECIFIED(不明确的大小)
- SpecSize (测量大小) 具体的一个值
为了便于理解parentView的MeasureSpac和子ViewMeasureSpac及其Layoutparams的关系。我这里有个小demo可供下载MeasureDemo
3. 总结measure流程
measre流程图.png
4. Layout流程
view的layout流程和measure流程类型,具体的目的就是要根据每个view的长宽,根据相应viewGroup实现类的规则放置view的位置。确定view的left,top,right,bottom的值。
5. draw流程
view的绘制。流程同上,一般来说针对的就是weight目录下的东西,和viewGroup就没啥关系了,根据各自textview,imageview等实现类,画出相应内容即可。
6. 关于自定义view
自定义View的内容推荐一个比较好的课程Hencoder