【Android】View的绘制机制与源码解析

本文详细探讨了Android中View的绘制机制,从Activity的视图结构到ViewTree的绘制流程,包括measure、layout和draw过程。通过源码解析,揭示了ViewRootImpl在UI绘制中的关键角色,以及invalidate方法如何触发重绘。文章还分析了measure参数、layout逻辑以及draw方法在View和ViewGroup中的实现。
摘要由CSDN通过智能技术生成

一、前言

Android的视图是如何绘制的?深入了解一下UI的绘制原理无论对我们APP的性能优化还是对我们的自定义view都有很大的帮助。

二、Activity的视图结构

先看一下activity的视图结构图:
在这里插入图片描述

每个activity都有一个Window(实际是phonewindow)
Phonewindow含有一个DecorView,这是我们window的topview
DecorView是继承自Framelayout,换言之其为整个ViewTree的根节点viewGroup
再看一下Phonewindow的类图:
在这里插入图片描述

接下来我们来看一下单个Activity的viewTree的结构,我选择了两版sdk来查看
(1)Android4.4系统的activity:
在这里插入图片描述

(2)Android6.0系统的activity:
在这里插入图片描述

三、ViewTree的绘制

id为“content”的ContentFrameLayout是我们的布局文件加载显示的区域,更确切地说是我们activity的setcontentView()方法设置的视图显示的区域。下面我么就看看ContentFrameLayout中整个viewTree是如何绘制出来的。
在这里插入图片描述

这些View应该都具有相同的绘制流程与机制才能显示到屏幕上(可能每个控件的具体绘制逻辑有差异, 但是主流程都是一样的)。每一个View的绘制过程都必须经历三个最主要的过程,也就是measure()、layout()和draw()。
先看一下类图:
在这里插入图片描述

那么,整个Android的UI绘制机制是从哪里开始的即入口在哪里呢?答案就是ViewRootImpl类的performTraversals()方法。ViewRootImpl这个类是一个隐藏类,所以如果你是使用Eclipse开发的话可能看不到这个文件(AndroidStudio可以),没关系,根据路径(androidSDK\android-sdk-windows\sources\android-23\android\view\)去找到ViewRootImpl.Java文件,然后用文本阅读工具直接打开就好。
看一下官方对ViewRootImpl的介绍:

 /** 
* The top of a view hierarchy, implementing the needed protocol between View
 * and the WindowManager. This is for the most part an internal implementation
 * detail of {@link WindowManagerGlobal}. 
* 
* {@hide} 
*/

上面这段注释啥意思呢?说白了就是ViewRootImpl是一个window中的viewTree的入口,实现了window对viewTree管理的必需逻辑。

ViewRootImpl类performTraversals()代码,源代码长的恐怖,这里给大家过滤一下

private void performTraversals() {
   
        ......
        //lp.width和lp.height在创建ViewGroup实例时值为MATCH_PARENT
        int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
        int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
        ......
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        ......
        performLayout(lp, desiredWindowWidth, desiredWindowHeight);
        ......
        performDraw();
        ......
    }
     
    //执行rootView的测量
    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
   
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
   
            //ViewGroup的measure()方法
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
   
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
      
    //执行layout操作
    private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
   
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;
        final View host = mView;
        ......
        try {
   
            //viewRoot先进行layout
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
            mInLayout = false;
            //需要layout的子view的数量
            int numViewsRequestingLayout = mLayoutRequesters.size();
            if (numViewsRequestingLayout > 0) {
   
                //需要layout的子view
                ArrayList<View> validLayoutRequesters = getValidLayoutRequesters(mLayoutRequesters,
                        false);
                if (validLayoutRequesters != null) {
   
                    //如果view中有调用requestLayout()方法,则说明界面需要刷新
                    mHandlingLayoutInLayoutRequest = true;
                    int numValidRequests = validLayoutRequesters.size();
                    for (int i = 0; i < numValidRequests; ++i) {
   
                        final View view = validLayoutRequesters.get(i);
                        view.requestLayout()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值