View绘制流程二:测量、布局、绘制

Android自定义View系列之详解View的绘制流程 一、开场白 开讲之前我们先预设一种自定义ViewGroup的场景:我们知道LinearLayout、FrameLayout、RelativeLayout...都是系统定义实现的布局,我们想要自定义一个FlowLayout流式布局实现我们自己要的效果(自定义不就是按照自己想要的效果实现的一种布局),流式布局目前Google官方还没帮我们提供,但网上有很多自定义的流式布局,也都是开发者们自己继承ViewGroup实现的,今天以自定义ViewGroup实现流式布局FlowLayout为大前提讲解View的绘. 阅读详情


上篇博客我们详细分析了布局是如何添加到我们的界面上的,谈到ViewRootImpl的三个方法也就停止了,今天我们详细的分析measure、layout、draw三个过程。

Measure

理解MeasureSpec

什么是MeasureSpec

当我们要对我们的View进行测量时,要有一定的规则,我们不仅要考虑开发者在xml中给我们指定的layout,而且还要结合父View给我们指定的测量规则,这两个属性共同决定了我们子View的MeasureSpec,也就是子View的测量规则,按照这个MeasureSpec,我们就可以很轻松的解决测量时可能会遇到的问题。

MeasureSpec是一个32位的int值,高2位是SpecMode,它指的是测量模式,低30位是、SpecSize,它指的是在某种测量模式下的规格大小。MeasureSpec是将这两个打包成一个int值来避免过多对象内存分配,在MeasureSpec类内部提供了对这两个属性的操作。

MeasureSpec分类
  • UNSPECIFIED

    父View不会对View有任何的限制,要多大给多大,这种情况一般用于系统内部。

  • EXACTLY

    父View已经测出View所需的精确的大小,这个时候View的最终大小就是SpecSize所指定的值。它对应LayoutParams中的match_parent和具体数值这两种模式。

  • AT_MOST

    父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么要看不同View的具体实现。它对应wrap_content属性。

MeasureSpec的创建

通过getChildMeasure就可以创建出子View的MeasureSpec:

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
    int specMode = MeasureSpec.getMode(spec);
    int specSize = MeasureSpec.getSize(spec);

    int size = Math.max(0, specSize - padding);

    int resultSize = 0;
    int resultMode = 0;

    switch (specMode) {
    // Parent has imposed an exact size on us
    case MeasureSpec.EXACTLY:
        if (childDimension >= 0) {
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // Child wants to be our size. So be it.
            resultSize = size;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // Child wants to determine its own size. It can't be
            // bigger than us.
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        }
        break;

    // Parent has imposed a maximum size on us
    case MeasureSpec.AT_MOST:
        if (childDimension >= 0) {
            // Child wants a specific size... so be it
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // Child wants to be our size, but our size is not fixed.
            // Constrain child to not be bigger than us.
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // Child wants to determine its own size. It can't be
            // bigger than us.
            resultSize = size;
            resultMode = MeasureSpec.AT_MOST;
        }
        break;

    // Parent asked to see how big we want to be
    case MeasureSpec.UNSPECIFIED:
        if (childDimension >= 0) {
            // Child wants a specific size... let him have it
            resultSize = childDimension;
            resultMode = MeasureSpec.EXACTLY;
        } else if (childDimension == LayoutParams.MATCH_PARENT) {
            // Child wants to be our size... find out how big it should
            // be
            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
            resultMode = MeasureSpec.UNSPECIFIED;
        } else if (childDimension == LayoutParams.WRAP_CONTENT) {
            // Child wants to determine its own size.... find out how
            // big it should be
            resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
            resultMode = MeasureSpec.UNSPECIFIED;
        }
        break;
    }
    //noinspection ResourceType
    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

上述代码一图以蔽之:

在这里插入图片描述

View的measure

有了MeasureSpec,我们也可以放心的去测量我们的View了。View的measure过程是由其measure方法来完成,measure方法是一个final方法,子类不可以重写此方法,在View的measure方法中会调用View的onMeasure方法,因此我们直接看onMeasure方法:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
            getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

这个方法里,只用了一个方法就完成了View的measure过程,而通过方法名我们也知道这个方法时设置测量尺寸,那么参数就是测量过的尺寸了,所以我们看getDefaultSize这个方法:

public static int getDefaultSize(int size, int measureSpec) {
    int result = size;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    switch (specMode) {
    case MeasureSpec.UNSPECIFIED:
        result = size;
        break;
    case MeasureSpec.AT_MOST:
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
}

这个方法也是很简单,UNSPECIFIED这个分支我们不去管他,而AT_MOST和EXACTLY这两个返回的结果是一样的,都是specSize,我们通过上面的表格也可以看出specSize是parentSize,是父View提供的可用空间。这就给我们自定义View提供了一个思路:继承View需要重写onMeasure并对wrap_content属性设置默认宽高,否则效果同match_parent一样,从源码我们也可以看出原因来。

ViewGroup的measure

对于ViewGroup来说,除了完成自己的measure过程以外,还要遍历的去调用所有子元素的measure方法,各个子元素再递归去执行这个过程。和View不同的是,ViewGroup是一个抽象类,因此它没有重写View的onMeasure方法,但是它提供了一个叫measureChildren的方法:

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
    final int size = mChildrenCount;
    final View[] children = mChildren;
    for (int i = 0; i < size; ++i) {
        final View child = children[i];
        if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
        }
    }
}

这个方法里,会对每一个子元素去执行ViewGroup的measureChild方法:

protected void measureChild(View child, int parentWidthMeasureSpec,
        int parentHeightMeasureSpec) {
    final LayoutParams lp = child.getLayoutParams();

    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
            mPaddingLeft + mPaddingRight, lp.width);
    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
            mPaddingTop + mPaddingBottom, lp.height);

    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}

这个方法里,获取了子View的MeasureSpec,然后对子View进行测量。在继承ViewGroup实现自定义ViewGroup时,测量完子View的宽高后,就可以确定ViewGroup自身的宽高了。

Layout

Layout的作用是ViewGroup用来确定子元素的位置的,当ViewGroup的位置被确定后,它会在onLayout方法中遍历所有的子元素并调用其layout方法,在layout方法中,onLayout方法又会被调用。layout方法是确定其本身的位置,而onLayout方法是去确定所有子元素的位置。

简单看一看layout方法:

public void layout(int l, int t, int r, int b) {
    if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {
        onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);
        mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
    }

    int oldL = mLeft;
    int oldT = mTop;
    int oldB = mBottom;
    int oldR = mRight;

    boolean changed = isLayoutModeOptical(mParent) ?
            setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

    if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
        onLayout(changed, l, t, r, b);

        if (shouldDrawRoundScrollbar()) {
            if(mRoundScrollbarRenderer == null) {
                mRoundScrollbarRenderer = new RoundScrollbarRenderer(this);
            }
        } else {
            mRoundScrollbarRenderer = null;
        }

        mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;

        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnLayoutChangeListeners != null) {
            ArrayList<OnLayoutChangeListener> listenersCopy =
                    (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();
            int numListeners = listenersCopy.size();
            for (int i = 0; i < numListeners; ++i) {
                listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);
            }
        }
    }

    final boolean wasLayoutValid = isLayoutValid();

    mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
    mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;

    if (!wasLayoutValid && isFocused()) {
        mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
        if (canTakeFocus()) {
            // We have a robust focus, so parents should no longer be wanting focus.
            clearParentsWantFocus();
        } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) {
            // This is a weird case. Most-likely the user, rather than ViewRootImpl, called
            // layout. In this case, there's no guarantee that parent layouts will be evaluated
            // and thus the safest action is to clear focus here.
            clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
            clearParentsWantFocus();
        } else if (!hasParentWantsFocus()) {
            // original requestFocus was likely on this view directly, so just clear focus
            clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
        }
        // otherwise, we let parents handle re-assigning focus during their layout passes.
    } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) {
        mPrivateFlags &= ~PFLAG_WANTS_FOCUS;
        View focused = findFocus();
        if (focused != null) {
            // Try to restore focus as close as possible to our starting focus.
            if (!restoreDefaultFocus() && !hasParentWantsFocus()) {
                // Give up and clear focus once we've reached the top-most parent which wants
                // focus.
                focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false);
            }
        }
    }

    if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) {
        mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
        notifyEnterOrExitForAutoFillIfNeeded(true);
    }

    notifyAppearedOrDisappearedForContentCaptureIfNeeded(true);
}

通过setFrame来设置View四个顶点的位置,即初始化mLeft、mRight、mTop、mBottom。四个顶点的位置确定了,View在父容器的位置也就确定了。

Draw

Draw的过程就简单了,它的作用就是将View绘制到屏幕上面。View的绘制遵循着如下几步:

  • 绘制背景 background.draw(canvas)
  • 绘制自己 onDraw
  • 绘制children dispatchDraw
  • 绘制装饰 onDrawScrollBars

这四个步骤在源码中也明显可以看出。View的onDraw是空实现,不同的控件对内容的绘制都不同,所以留给控件自己实现,我们自定义View时需要重写onDraw方法来绘制我们自己的控件。在ViewGroup中,也有对dispatchDraw的实现,dispatchDraw中对子View进行遍历,并调用了drawChild方法,其中又调用了View的draw方法,完成对子View的绘制。

自定义View时注意以下问题

  1. 让View支持wrap_content。
  2. 如果有必要,支持padding。
  3. 尽量不要在View中使用Handler。
  4. View中如果有线程或者动画,及时停止。
  5. View带有滑动嵌套情景时,处理好滑动冲突。
自定义View:测量measure,布局layout,绘制draw 什么是View在Android的官方文档中是这样描述的:表示了用户界面的基本构建模块。一个View占用了屏幕上的一个矩形区域并且负责界面绘制和事件处理。手机屏幕上所有看得见摸得着的都是View。这一点对所有图形系统来说都一样,例如ios的UIView。View和Activity的区别我们之前学习过android的四大组件,Activity是四大组件中唯一一个用来和用户进行交互的组件。可以说Activ 阅读详情

相关推荐

View和ViewGroup,View绘制流程解析

View是绘制在屏幕上的用户能与之交互的一个对象,它代表了用户界面组件的一块可绘制的空间块,每一个空间块在屏幕上占据一个长方 形区域。View 的绘制流程是从 ViewRootImpl 的 performTraversals() 方法开始的,它经过测量(measure)、放置(layout)和绘制(draw)三个过程才能把一个 View 绘制出来,measure() 方法用于测量 View 的宽高,layout() 用于确定 View 在父容器中的放置位置,draw() 负责做具体的绘制操作。

qq_45730283的博客 1404

Android View的工作流程(三) layout过程

可以看到View的layout方法中会先通过setFrame方法设置mLeft、mTop、mRight、mBottom来确定当前View在父布局中的位置,接着会调用onLayout方法去确定当前View下的子View在当前View中的位置。而mRight和mLeft都是在onLayout方法中确定的,所以在默认的测量方式下,getMeasuredWidth和getWidth的最终取值应该是相等的,只不过getMeasuredWidth赋值于measure的过程中比getWidth赋值要早一些。...

qq_37159335的博客 787

Android View工作原理:测量、布局、绘制流程 & 自定义View

#.概述 ##.PhoneWindow中的DecorView是根布局 Android中Window是显示和管理View的载体,其实现类是PhoneWindow。 所有View是按照树的逻辑结构来管理的,父View有多个子View节点,子View节点又可以有多个View节点。 而这棵View树的根节点是PhoneWindow中的根布局,一个DecorView,DecorView由两部分构成: ActionBar(操作条区域,顶部用于显示标题和几个操作...

u013914309的博客 1314

android View的绘制流程

View的绘制流程 View的绘制主要指measure、layout、draw三大流程,即测量、布局和绘制。其中measure确定view的测量宽高,layout确定view的最终宽高和四个顶点的位置,draw则是将view绘制在屏幕上。 一、mesure过程 measure过程要分开来看,如果是单纯的原始view,那么通过measure就可以完成其测量过程。如果是一个ViewGroup,除了完成...

m0_37194191的博客 378

(View体系一)View的测量(Measure)、布局(Layout)、绘制(Draw)流程的完整细节?

测量流程自顶向下递归。父View通过将约束传递给子View,子View通过onMeasure确定自己的尺寸。核心是解决‘有多大’的问题。布局流程自顶向下递归。父View根据测量结果和布局规则,在onLayout中确定所有子View的位置。核心是解决‘在哪里’的问题。绘制流程自顶向下递归。每个View在onDraw中绘制自己,ViewGroup在中委托子View绘制。核心是解决‘长什么样’的问题。减少测量深度:扁平化的View层级能显著减少onMeasure的递归调用次数。避免无效绘制:通过。

augfun的博客 716

Android View的绘制流程三部曲

如果我们用面向对象的思维方式来思考,就会觉的View的绘制机制是很合理,很科学的。我们要在一张纸上画一幅画,首先我们要测量一下这幅画有多大吧,然后确定在纸的哪个地方画会显得比较美观,最后才是用画笔工具将画绘制在纸上。 在Android中也是一样的。View的绘制流程主要是指measure,layout,draw这三步,即测量,布局,绘制。首先是要测量View的宽高,然后布局确定在父容器中的位置坐标,最后才是绘制

yinhuanxu 5212

Android进阶知识:绘制流程(中)

1、前言 在Android进阶知识:绘制流程(上)中主要是关于绘制流程中会遇到的基础知识,这一篇开始来看具体View绘制的流程。前篇中讲过View分为ViewGroup和一般的View,ViewGroup中可以包含其他View或ViewGroup,并且ViewGroup继承了View,所以绘制流程中ViewGroup相比一般View除了要绘制自身还要绘制其子View。View的绘制流程分为三个阶段...

weixin_30929295的博客 180

从零构建:Trinamic API在STM32上的深度移植与TMC-IDE通信实战

本文详细介绍了如何从零开始在STM32平台上深度移植Trinamic API,并实现与TMC-IDE工具的稳定通信。内容涵盖SPI底层驱动定制、寄存器配置、高级功能实现及调试技巧,重点解析了TMC5160芯片的集成实践,帮助开发者构建可靠的嵌入式运动控制系统。

w1x2y3的博客 255

面试博弈:掰扯5分钟View的生命周期

面试就是一次技术的博弈过程,能唬住面试官就是胜利。如果每当面试官提出一个问题,都能掰扯5分钟,想必会给面试官一个不错的印象。同时,我们也可以将面试官的问题向自己擅长的领域引导,进而在面试过程中起到正向的引导作用。 然而,面试过程中经常不知道该说什么,又该从何说起。本文将串一下相关知识点。帮助你轻松凑够5分钟~~

vchao的博客 1130

Transformer-Based Attention Networks for Continuous Pixel-Wise Prediction 基于Transformer注意力网络连续像素级与估计

Transformer-Based Attention Networks for Continuous Pixel-Wise Prediction 基于Transformer注意力网络的连续的像素级的

MengYa_Dream的博客 4717

Ansys Maxwell磁场仿真入门:无线传能线圈自感与互感计算全流程

本文详细介绍了使用Ansys Maxwell进行无线充电线圈磁场仿真的全流程,包括模型建立、求解器设置、电感参数提取及优化策略。通过实战案例,帮助工程师掌握线圈自感与互感计算技巧,提升无线充电系统设计效率与精度。重点解析了Maxwell在磁场仿真中的关键应用,适用于电磁场仿真初学者和进阶用户。

weixin_29047545的博客 443

Android O: View的绘制流程(二):测量

本文开始分析View的测量的流程。

橡果生长记的博客 1424

音视频开发—H264相关概念和压缩原理详解(GOP、宏块、帧内压缩、帧间压缩)

本文讲述了H264相关概念和原理——GOP概念,SPS与PPS,帧内压缩原理,帧间压缩原理,解释了什么是运动补偿,什么运动矢量等等概念

weixin_46999174的博客 3982

Android View绘制流程

前言     在学习安卓的时候免不了和布局文件打交道,一直都想弄清楚内部究竟是个什么原理,于是有了这篇文章。     这篇文章形成与多个大神的文章集和,算是帮大家简单过滤一下关键信息,相信看完后能够基本上了解绘制流程是个什么样子。(无安卓基础的话可能有点难懂hhh) View绘制流程     View 的绘制流程分为三步:在自定义View的时候一般需要重写父类的onMeasure()、onLayout()、onDraw()三个方法,来完成视图的展示过程。当然,这三个暴露给开发者重写的方法只不过是整个绘制流程

weixin_41607932的博客 1万+

Android音频学习(十四)——加载音频设备

loadHwModule 是 Android 音频系统的核心初始化函数,负责加载音频硬件抽象层(HAL)的模块实现。它建立 AudioPolicyService 与底层硬件的桥梁,将配置文件(audio_policy_config.xml)中的标签<module>定义转化为可操作的硬件对象,加载的是音频硬件模块(HAL实现),每个模块对应一种音频设备类型,以动态库的形式存在,负责与底层音频硬件交互。

miemie2014的博客 1732

【LaTex】3.5 数据分析

简述了LaTex柱状图、饼图、折线图的画法。

你的指尖有改变世界的力量 5891

浅析Android View的测量布局流程

从测量流程的分析中,总结出自定义View需要注意的事项:自定义View的从上面的源码分析中可以得知,onMeasure的默认实现是将等同于进行处理,因此自定义View时需要注意对这种情况的处理。解决办法是通过对onMeasure方法进行重写,实现对模式的特殊处理,即判断布局参数是否为,是的话则调用方法并传入具体数值。自定义View的padding参数通过上面源码的分析可以知道,容器类型的View比如都会通过ViewGroup的方法将自身的padding和子View的margin。

boker_han的博客 1355

STM32实战开发(99):基于STM32的智能交通灯控制系统设计与实现

随着城市化进程的加速和交通流量的不断增长,传统的交通灯控制系统已逐渐不能满足现代城市交通管理的需求。为了更好地提高交通效率、减少交通拥堵、降低事故发生率,智能交通灯控制系统成为了解决这一问题的重要途径。通过智能算法和自动化控制,智能交通灯控制系统能够根据实时交通流量和交通状况来自动调整红绿灯的切换,从而优化交通流和提高交通安全。STM32作为一款高性能的微控制器,具备较强的运算能力、丰富的外设接口和优良的功耗表现,非常适合用来设计和开发智能交通灯控制系统。

2201_76125393的博客 1218

View的绘制流程

View绘制的三大流程主要指:measure(测量)、layout(布局)、draw(绘制)。measure过程中确定View的尺寸(即宽高),layout过程中确定View的位置(即上下左右的位置),draw过程确定View显示的内容。在开发中,通常都是在Activity的onCreate()中调用setContentView(R.layout.custom_layout)来实现想要的页面布局。...

走向远方 2373

Modelsim:LPDDR5仿真(含美光仿真模型官方sv&vcs代码)

虽然,三星在设计跟量产上,早于其他家存储产商,但是镁光后来居上了,是业界首家支持全速 LPDDR5 的供应商,并且开发者在做开发的时候,也是用美光颗粒比较多,所以这里就先以美光的仿真模型为主进行仿真。 本工程为美光官方工程,支持Modelsim、VCS、ncverilog三种仿真器仿真。模型破解过,为完整system-verilog代码。

千歌叹尽执夏的博客 1287

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

View绘制源码浅析(二)布局的测量、布局、绘制

前言 在第一篇View绘制源码浅析(一)布局的加载我们知道了setContentView()完成了DecorView的创建,并且将xml中的布局标签转换成了对应的View、属性转换成了对应的LayoutParams然后添加到了id为content的布局上,也就是说完成了布局对象的创建并且和DecorView关联上了。 那么第二篇将介绍View是如何显示出来的,主体流程可分为测量、布局、绘制这三步。...

朱利源的博客 513

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Android View绘制流程详解

除了使用系统提供的View,我们还可以自定义View来实现特定的绘制效果。自定义View的绘制过程与系统View的绘制流程类似,只需要在onLayout()和onDraw()方法中实现自己的逻辑即可。自定义View的绘制过程可以通过以下步骤来完成:重写方法,根据自己的需求计算出View的测量宽度和高度。重写onLayout()方法,根据测量结果和父容器的布局参数,确定View在父容器中的位置和大小。重写onDraw()方法,根据需要绘制自定义的内容。在onDraw()方法中,可以使用Canvas。

jiet_h的博客 2924

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Android View的测量、布局、绘制

Android View的测量,布局,绘制源码分析

牛永志的专栏 1161

Android View 绘制流程之一:measure测量

Android View 绘制流程之一:measure测量一.MeasureSpec测量规格二.LayoutParams布局参数1.ViewaddViewLinearLayout的generateDefaultLayoutParams2.xml三.Measure整体流程四.常见onMeasure实现1.测量子View方法(1)measureChildren()(2)measureChild()(3...

依生依世 1577

Android View的测量、布局、绘制过程详解(上)

Android View的绘制过程主要有三步: 测量 Measure 布局 Layout 绘制 Draw 首先理解MeasureSpec的含义,然后跟踪ViewGroup的measure、layout、draw三个方法即可 view的绘制流程是我们在自定义View中通常会使用到的一个知识点,也是一个面试常问的点。简直是Android开发必备知识。 1、理解ViewRootImpl和DecorV...

追yi流年 1797

Android视图绘制流程完全解析,带你一步步深入了解View(二)

在上一篇文章中,我带着大家一起剖析了一下LayoutInflater的工作原理,可以算是对View进行深入了解的第一步吧。那么本篇文章中,我们将继续对View进行深入探究,看一看它的绘制流程到底是什么样的。如果你还没有看过我的上一篇文章,可以先去阅读 Android LayoutInflater原理分析,带你一步步深入了解View(一) 。 相信每个Android程序员都知道,我们每天的开发工作当中都在不停地跟View打交道,Android中的任何一个布局、任何一个控件其实都是直接或间接继承自View的,

郭霖的专栏 24万+
上一篇: View绘制流程一:布局是如何添加到界面上的
下一篇: Java基础总结一(概述、基础知识)
<天各一方>
博客等级 码龄6年 17粉丝 17原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值