• 自定义View绘制流程


    View绘制

    View绘制流程

    1. 出发addView流程:
      在这里插入图片描述
    2. performTraversals流程
      在这里插入图片描述
      在这里插入图片描述

    startActivity->ActivityThread.handleLaunchActivity->onCreate ->完成DecorView和Activity的创建->handleResumeActivity->onResume()->DecorView添加到WindowManager->ViewRootImpl.performTraversals()方法,测量(measure),布局(layout),绘制(draw), 从DecorView自上而下遍历整个View树。

    Measure:测量视图宽高。 单一View:measure() -> onMeasure() -> getDefaultSize() 计算View的宽/高值 ->setMeasuredDimension存储测量后的View宽 / 高 ViewGroup: -> measure() -> 需要重写onMeasure( ViewGroup没有定义测量的具体过程,因为ViewGroup是一个抽象类,其测量过程的onMeasure方法需要各个子类去实现。如:LinearLayout、RelativeLayoutFrameLayout等等,这些控件的特性都是不一样的,测量规则自然也都不一样。)遍历测量ViewGroup中所有的View -> 根据父容器的MeasureSpec和子View的LayoutParams等信息计算子View的MeasureSpec -> 合并所有子View计算出ViewGroup的尺寸 ->setMeasuredDimension 存储测量后的宽 / 高从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。

    Layout:先通过 measure 测量出 ViewGroup 宽高,ViewGroup 再通过 layout 方法根据自身宽高来确定自身位置。当 ViewGroup 的位置被确定后,就开始在 onLayout 方法中调用子元素的 layout 方法确定子元素的位置。子元素如果是 ViewGroup 的子类,又开始执行onLayout,如此循环往复,直到所有子元素的位置都被确定,整个View 树的 layout 过程就执行完了。

    Draw:绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;⑤、还原图层(Layer);⑥、绘制View的装饰(例如滚动条等等)。

    MeasureSpec

    MeasureSpec表示的是一个32位的整形值,它的高2位表示测量模式SpecMode,低30位表示某种测量模式下的
    规格大小SpecSize。MeasureSpec是View类的一个静态内部类,用来说明应该如何测量这个View。它由三种测量模
    式,如下:

    • EXACTLY:精确测量模式,视图宽高指定为match_parent或具体数值时生效,表示父视图已经决定了子视图的
      精确大小,这种模式下View的测量值就是SpecSize的值。
    • AT_MOST:最大值测量模式,当视图的宽高指定为wrap_content时生效,此时子视图的尺寸可以是不超过父视
      图允许的最大尺寸的任何尺寸。
    • UNSPECIFIED:不指定测量模式, 父视图没有限制子视图的大小,子视图可以是想要的任何尺寸,通常用于系统
      内部,应用开发中很少用到。
    • MeasureSpec通过将SpecMode和SpecSize打包成一个int值来避免过多的对象内存分配,为了方便操作,其提
      供了打包和解包的方法,打包方法为makeMeasureSpec,解包方法为getMode和getSize。

    子View创建MeasureSpec创建规则是什么

    根据父容器的MeasureSpec和子View的LayoutParams等信息计算子View的MeasureSpec
    在这里插入图片描述

    自定义View.wrap_content不起作用的原因

    1.因为onMeasure()->getDefaultSize(),当View的测量模式是AT_MOST或EXACTLY时,View的大小都会被设置
    成子View MeasureSpec的specSize。

    public static int getDefaultSize(int size, int measureSpec) {
    	switch (specMode) {
    		case MeasureSpec.UNSPECIFIED: result = size; break; 
    		case MeasureSpec.AT_MOST: 
    		case MeasureSpec.EXACTLY: result = specSize; 
    		break;
    	}
    	return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.View的MeasureSpec值是根据子View的布局参数(LayoutParams)和父容器的MeasureSpec值计算得来,具体计算逻辑封装在getChildMeasureSpec()。 当子View wrap_content或match_parent情况下,子ViewMeasureSpec的specSize被设置成parenSize = 父容器当前剩余空间大小

    旧的

    开始

    构造函数

    onMeasure

    onSizeChanged

    onLayout

    onDraw

    视图状态改变

    结束

    Android View 的绘制流程之 Measure 过程详解 (一)

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    密码学 | RC4算法Native层分析
    使用centos搭建内网的yum源
    离散型制造业数字化转型难点与转型方向
    redis中数据类型命令整理
    合格论文的七个要素!
    Docker24:compose下载安装步骤 + compose核心概念 +常用命令
    Log4j 2.16.0发布,受Log4j漏洞影响的Apache项目一览
    QComboBox的信号
    设计模式面试八股文
    C#:Winform界面中英文切换功能
  • 原文地址:https://blog.csdn.net/AdrianAndroid/article/details/107354852