我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android View 绘制机制的详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android View 绘制机制的详解

View 绘制机制一、

View 树的绘图流程

当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理.绘制是从根节点开始,对布局树进行 measure 和 draw。整个 View 树的绘图流程在ViewRoot.java类的performTraversals()函数展开,该函数所做 的工作可简单概况为是否需要重新计算视图大小(measure)、是否需要重新安置视图的位置(layout)、以及是否需要重绘(draw),流程图如下:
Android View 绘制机制的详解

View 绘制流程函数调用链
Android View 绘制机制的详解

需要说明的是,用户主动调用 request,只会出发 measure 和 layout 过程,而不会执行 draw 过程

二、 概念

1. measure 和 layout

从整体上来看 Measure 和 Layout 两个步骤的执行:

Android View 绘制机制的详解

树的遍历是有序的,由父视图到子视图,每一个 ViewGroup 负责测绘它所有的子视图,而最底层的 View 会负责测绘自身。

2. 具体分析

measure 过程由measure(int, int)方法发起,从上到下有序的测量 View,在 measure 过程的最后,每个视图存储了自己的尺寸大小和测量规格。
layout 过程由layout(int, int, int, int)方法发起,也是自上而下进行遍历。在该过程中,每个父视图会根据 measure 过程得到的尺寸来摆放自己的子视图。

measure 过程会为一个 View 及所有子节点的 mMeasuredWidth 和 mMeasuredHeight 变量赋值,该值可以通过 getMeasuredWidth()和getMeasuredHeight()方法获得。而且这两个值必须在父视图约束范围之内,这样才可以保证所有的父视图都接收所有子视图的测量。如果子视图对于 Measure 得到的大小不满意的时候,父视图会介入并设置测量规则进行第二次 measure。比如,父视图可以先根据未给定的 dimension 去测量每一个子视图,如果最终子视图的未约束尺寸太大或者太小的时候,父视图就会使用一个确切的大小再次对子视图进行 measure。

3. measure 过程传递尺寸的两个类

  • ViewGroup.LayoutParams (View 自身的布局参数)
  • MeasureSpecs 类(父视图对子视图的测量要求)

ViewGroup.LayoutParams

这个类我们很常见,就是用来指定视图的高度和宽度等参数。对于每个视图的 height 和 width,你有以下选择:

  • 具体值
  • MATCH_PARENT 表示子视图希望和父视图一样大(不包含 padding 值)
  • WRAP_CONTENT 表示视图为正好能包裹其内容大小(包含 padding 值)

ViewGroup 的子类有其对应的 ViewGroup.LayoutParams 的子类。比如 RelativeLayout 拥有的 ViewGroup.LayoutParams 的子类 RelativeLayoutParams。

有时我们需要使用 view.getLayoutParams() 方法获取一个视图 LayoutParams,然后进行强转,但由于不知道其具体类型,可能会导致强转错误。其实该方法得到的就是其所在父视图类型的 LayoutParams,比如 View 的父控件为 RelativeLayout,那么得到的 LayoutParams 类型就为 RelativeLayoutParams。

MeasureSpecs

测量规格,包含测量要求和尺寸的信息,有三种模式:

UNSPECIFIED

父视图不对子视图有任何约束,它可以达到所期望的任意尺寸。比如 ListView、ScrollView,一般自定义 View 中用不到,

EXACTLY

父视图为子视图指定一个确切的尺寸,而且无论子视图期望多大,它都必须在该指定大小的边界内,对应的属性为 match_parent 或具体值,比如 100dp,父控件可以通过MeasureSpec.getSize(measureSpec)直接得到子控件的尺寸。

AT_MOST

父视图为子视图指定一个最大尺寸。子视图必须确保它自己所有子视图可以适应在该尺寸范围内,对应的属性为 wrap_content,这种模式下,父控件无法确定子 View 的尺寸,只能由子控件自己根据需求去计算自己的尺寸,这种模式就是我们自定义视图需要实现测量逻辑的情况。

3、 measure 核心方法

measure(int widthMeasureSpec, int heightMeasureSpec)
该方法定义在View.java类中,为 final 类型,不可被复写,但 measure 调用链最终会回调 View/ViewGroup 对象的 onMeasure()方法,因此自定义视图时,只需要复写 onMeasure() 方法即可。

onMeasure(int widthMeasureSpec, int heightMeasureSpec)

该方法就是我们自定义视图中实现测量逻辑的方法,该方法的参数是父视图对子视图的 width 和 height 的测量要求。在我们自身的自定义视图中,要做的就是根据该 widthMeasureSpec 和 heightMeasureSpec 计算视图的 width 和 height,不同的模式处理方式不同。

setMeasuredDimension()

测量阶段终极方法,在 onMeasure(int widthMeasureSpec, int heightMeasureSpec) 方法中调用,将计算得到的尺寸,传递给该方法,测量阶段即结束。该方法也是必须要调用的方法,否则会报异常。在我们在自定义视图的时候,不需要关心系统复杂的 Measure 过程的,只需调用setMeasuredDimension()设置根据 MeasureSpec 计算得到的尺寸即可,你可以参考 ViewPagerIndicator 的 onMeasure 方法。

下面我们取 ViewGroup 的 measureChildren(int widthMeasureSpec, int heightMeasureSpec) 方法对复合 View 的 Measure 流程做一个分析:

MeasureChild 的方法调用流程图:
Android View 绘制机制的详解

源码分析

  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);      }    }  }  protected void measureChild(View child, int parentWidthMeasureSpec,      int parentHeightMeasureSpec) {    final LayoutParams lp = child.getLayoutParams();//获取 Child 的 LayoutParams    final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,// 获取 ChildView 的 widthMeasureSpec        mPaddingLeft + mPaddingRight, lp.width);    final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,// 获取 ChildView 的 heightMeasureSpec        mPaddingTop + mPaddingBottom, lp.height);    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);  }    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {      .........    // 根据获取到的子视图的测量要求和大小创建子视图的 MeasureSpec    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);   }    public final void measure(int widthMeasureSpec, int heightMeasureSpec) {   ...   onMeasure(widthMeasureSpec, heightMeasureSpec);   ...  }  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),        getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));  }

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android View 绘制机制的详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android View 绘制机制的详解

View 绘制机制一、 View 树的绘图流程当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理.绘制是从根节点开始,对布局树进行 measure 和 draw。整个 View 树
2023-05-31

Android View如何绘制

上文说道了Android如何测量,但是一个漂亮的控件我只知道您长到哪儿,这当然不行。只需要简单重写OnDraw方法,并在Canvas(画布)对象上调用那根五颜六色的画笔就能够画出这控件"性感"的外表。那么View又是如何进行绘制了?要了解V
2022-06-06

Android View 事件分发机制详解

Android开发,触控无处不在。对于一些 不咋看源码的同学来说,多少对这块都会有一些疑惑。View事件的分发机制,不仅在做业务需求中会碰到这些问题,在一些面试笔试题中也常有人问,可谓是老生常谈了。我以前也看过很多人写的这方面的文章,不是说
2022-06-06

Android View事件分发机制详解

准备了一阵子,一直想写一篇事件分发的文章总结一下,这个知识点实在是太重要了。 一个应用的布局是丰富的,有TextView,ImageView,Button等,这些子View的外层还有ViewGroup,如RelativeLayout,Lin
2022-06-06

View绘制体系AttributeSet与TypedArray详解

View绘制体系中的AttributeSet和TypedArray是用于解析和处理XML布局文件中的属性值的工具。AttributeSet是一个接口,用于表示一个XML布局文件中的属性集合。它提供了一系列方法来获取属性的值,例如getAtt
2023-09-14

Android自定义View实现绘制虚线的方法详解

前言说实话当第一次看到这个需求的时候,第一反应就是Canvas只有drawLine方法,并没有drawDashLine方法啊!这咋整啊,难道要我自己做个遍历不断的drawLine?不到1秒,我就放弃这个想法了,因为太恶心了。方法肯定是有的,
2023-05-31

Android View 绘制流程(Draw)全面解析

前言 前几篇文章,笔者分别讲述了DecorView,measure,layout流程等,接下来将详细分析三大工作流程的最后一个流程——绘制流程。测量流程决定了View的大小,布局流程决定了View的位置,那么绘制流程将决定View的样子,一
2022-06-06

android view绘制流程是什么

Android View 绘制流程如下:1. 在 ViewRootImpl 中调用 performTraversals() 方法,开始绘制流程。2. 调用 ViewRootImpl 中的 performMeasure() 方法进行测量操作。
2023-09-22

深入浅析Android中View的绘制流程

深入浅析Android中View的绘制流程?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。从performDraw说起三大工作流程始于ViewRootImpl#p
2023-05-31

Android视图的绘制流程(上) View的测量

综述View的绘制流程可以分为三大步,它们分别是measure,layout和draw过程。measure表示View的测量过程,用于测量View的宽度和高度;layout用于确定View在父容器的位置;draw则是负责将View绘制到屏幕
2022-06-06

Android View的事件分发机制

一.Android View框架提供了3个对事件的主要操作概念。 1、事件的分发机制,dispatchTouchEvent。主要是parent根据触摸事件的产生位置,以及child是否愿意负责处理该系列事件等状态,向其child分发事件的机
2022-06-06

Android 绘制太极图实例详解

Android 绘制太极图 绘制一个太极图实现代码:package com.jackie.taijicircle; import android.content.Context; import android.graphics.Canv
2022-06-06

Android中View绘制的三大流程是什么

这篇文章主要介绍了Android中View绘制的三大流程是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。最近对Android中View的绘制机制有了一些新的认识,所以想记
2023-05-30

Android listView 绘制表格实例详解

Android listView 绘制表格 效果图:二,创建步骤: 1,创建布局:activity_main中的布局:2022-06-06

13问13答全面学习Android View绘制

本文通过13问13答学习Android View绘制,供大家参考,具体内容如下 1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,l
2022-06-06

Android自定义View绘制随机生成图片验证码

本篇文章讲的是Android自定义View之随机生成图片验证码,开发中我们会经常需要随机生成图片验证码,但是这个是其次,主要还是想总结一些自定义View的开发过程以及一些需要注意的地方。 按照惯例先看看效果图:一、先总结下自定义View的步
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录