Android中的view绘制流程,简单理解

简单理解

Android中的View类代表用户界面中基本的构建块。一个View在屏幕中占据一个矩形区域、并且负责绘制和事件处理。View是所有widgets的基础类,widgets是我们通常用于创建和用户交互的组件,比如按钮、文本输入框等等。子类ViewGroup是所有布局(layout)的基础类。layout是一个不看见的容器,里面堆放着其他的view或者ViewGroup,并且设置他们的布局属性。

所有的view在窗口中是以树状结构来管理。你可以通过代码或者编辑xml布局文件来添加一个view。view有很多的子类来负责控制或者有能力展示图片,文字等。

Android绘制View

当一个Activity启动时,会被要求绘制出它的布局。Android框架会处理这个请求,当然前提是Activity提供了合理的布局。绘制从根视图开始,从上至下遍历整棵视图树,每一个ViewGroup负责让自己的子View被绘制,每一个View负责绘制自己,通过draw()方法.绘制过程分三步走。

  • Measure
  • Layout
  • Draw

整个绘制流程是在ViewRoot中的performTraversals()方法展开的。部分源代码如下。

private void performTraversals() {......//最外层的根视图的widthMeasureSpec和heightMeasureSpec由来//lp.width和lp.height在创建ViewGroup实例时等于MATCH_PARENTint childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);......mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);......mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());......mView.draw(canvas);......
}

在绘制之前当然要知道view的尺寸和绘制。所以先进行measu和layout(测量和定位),如下图。

Measure过程

public final void measure(int widthMeasureSpec, int heightMeasureSpec) {  //....  
​//回调onMeasure()方法    onMeasure(widthMeasureSpec, heightMeasureSpec);  
​//more  
}

计算view的实际大小,获得高宽存入mMeasuredHeight和mMeasureWidth,measure(int, int)传入的两个参数。MeasureSpec是一个32位int值,高2位为测量的模式,低30位为测量的大小。测量的模式可以分为以下三种。

  • EXACTLY

精确值模式,当layout_width或layout_height指定为具体数值,或者为match_parent时,系统使用EXACTLY。

  • AT_MOST

最大值模式,指定为wrap_content时,控件的尺寸不能超过父控件允许的最大尺寸。

  • UNSPECIFIED

不指定测量模式,View想多大就多大,一般不太使用。

根据上面的源码可知,measure方法不可被重写,自定义时需要重写的是onMeasure方法

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

查看源码可知最终的高宽是调用setMeasuredDimension()设定的,如果不重写,默认是直接调用getDefaultSize获取尺寸的。

使用View的getMeasuredWidth()和getMeasuredHeight()方法来获取View测量的宽高,必须保证这两个方法在onMeasure流程之后被调用才能返回有效值。

Layout过程

Layout方法就是用来确定view布局的位置,就好像你知道了一件东西的大小以后,总要知道位置才能画上去。

mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());

layout获取四个参数,左,上,右,下坐标,相对于父视图而言。这里可以看到,使用了刚刚测量的宽和高。

public void layout(int l, int t, int r, int b) {int oldL = mLeft;int oldT = mTop;int oldB = mBottom;int oldR = mRight;boolean changed = setFrame(l, t, r, b);if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {.....onLayout(changed, l, t, r, b);.....
}

通过setFrame设置坐标。如果坐标改变过了,则重新进行定位。如果是View对象,那么onLayout是个空方法。因为定位是由ViewGroup确定的。

当layout结束以后getWidth()与getHeight()才会返回正确的值。

这里出现一个问题,getWidth/Height() 和 getMeasuredWidth/Height()有什么区别?

  • getWidth():View在设定好布局后整个View的宽度。
  • getMeasuredWidth():对View上的內容进行测量后得到的View內容占据的宽度

Draw过程

public void draw(Canvas canvas) {....../** Draw traversal performs several drawing steps which must be executed* in the appropriate order:**      1. Draw the background*      2. If necessary, save the canvas' layers to prepare for fading*      3. Draw view's content*      4. Draw children*      5. If necessary, draw the fading edges and restore layers*      6. Draw decorations (scrollbars for instance)*/
​// Step 1, draw the background, if needed......if (!dirtyOpaque) {drawBackground(canvas);}
​// skip step 2 & 5 if possible (common case)......
​// Step 2, save the canvas' layers......if (drawTop) {canvas.saveLayer(left, top, right, top + length, null, flags);}......
​// Step 3, draw the contentif (!dirtyOpaque) onDraw(canvas);
​// Step 4, draw the childrendispatchDraw(canvas);
​// Step 5, draw the fade effect and restore layers......if (drawTop) {matrix.setScale(1, fadeHeight * topFadeStrength);matrix.postTranslate(left, top);fade.setLocalMatrix(matrix);p.setShader(fade);canvas.drawRect(left, top, right, top + length, p);}......
​// Step 6, draw decorations (scrollbars)onDrawScrollBars(canvas);......}

重点是第三步调用onDraw方法。其它几步都是绘制一些边边角角的东西比如背景、scrollBar之类的。其中dispatchDraw,是用来递归调用子View,如果没有则不需要。本文主要解析了Android view的绘制,更深入的学习或者Android开发进阶,可以前往《Android核心架构笔记》查看详细的学习类目。

总结

  • View是Android中可视化UI组件的实体。
  • View的呈现依赖于Activity,是Activity所容纳的基本元素。
  • View主要提供了组件绘制和事件处理的方法。
  • View可以分为容器类型和实体类型。
  • 容器类型的View(ViewGroup)可容纳其它的容器类型View和实体类型View。
  • 实体类型的View主要用于用户交互,如:按钮,文本框。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/69373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【网络安全带你练爬虫-100练】第23练:文件内容的删除+写入

目录 0x00 前言: 0x02 解决: 0x00 前言: 本篇博文可能会有一点点的超级呆 0x02 解决: 你是不是也会想: 使用pyrhon将指定文件夹位置里面的1.txt中数据全部删除以后---->然后再将参数req_text的值写入到1.txt …

HDFS HA 高可用集群搭建详细图文教程

目录 一、高可用(HA)的背景知识 1.1 单点故障 1.2 如何解决单点故障 1.2.1 主备集群 1.2.2 Active、Standby 1.2.3 高可用 1.2.4 集群可用性评判标准(x 个 9) 1.3 HA 系统设计核心问题 1.3.1 脑裂问题 1.3.2 数据状…

Pytorch从零开始实战01

Pytorch从零开始实战——MNIST手写数字识别 文章目录 Pytorch从零开始实战——MNIST手写数字识别环境准备数据集模型选择模型训练可视化展示 环境准备 本系列基于Jupyter notebook,使用Python3.7.12,Pytorch1.7.0cu110,torchvision0.8.0&…

【二等奖方案】大规模金融图数据中异常风险行为模式挖掘赛题「冀科数字」解题思路

第十届CCF大数据与计算智能大赛(2022 CCF BDCI)已圆满结束,大赛官方竞赛平台DataFountain(简称DF平台)正在陆续释出各赛题获奖队伍的方案思路,欢迎广大数据科学家交流讨论。 本方案为【大规模金融图数据中…

Github 下载指定文件夹(git sparse-checkout)

比如要下载这里的 data_utils 步骤 1、新建空文件夹,并进入新建的空文件夹。 2、git init 初始化 3、git remote add origin 添加远程仓库 4、git config core.sparsecheckout true 允许稀疏检出 5、git sparse-checkout set 设置需要拉取的文件夹(可…

Docker Desktop 设置镜像环境变量

点击run 展开Optional settings container name :容器名称 Ports:根据你需要的端口进行输入,不输入则默认 后面这个 比如我这个 5432 Volumes:卷,也就是做持久化 需要docker 数据保存的地方 Environment variables…

解决C++ 遇笔试题输入[[1,2,3,...,],[5,6,...,],...,[3,1,2,...,]]问题

目录 0 引言1 思路2 测试结果3 完整代码4 总结 0 引言 现在面临找工作问题,做了几场笔试,遇到了一个比较棘手的题目就是题目输入形式如下: [ [3,1,1], [3,5,3], [3,2,1] ] 当时遇到这个问题还是比较慌的,主要是之前没有遇到这样的…

【STM32】锁存器

问题背景 在学习FSMC控制外部NOR存储器时,看到在NOR复用接口模式下,AD信号[15:0]是复用的。也就是说,若不使用锁存器:当NADV为低时,ADx(x0…15)上出现地址信号Ax,当NADV变高时,ADx上出现数据信号Dx。若使用…

9.3.3网络原理(网络层IP)

一.报文: 1.4位版本号:IPv4和IPv6(其它可能是实验室版本). 2.4位首部长度:和TCP一样,可变长,带选项,单位是4字节. 3.8位服务类型 4.16位总长度:IP报头 IP载荷 传输层是不知道载荷长度的,需要网络层来计算. IP报文 - IP报头 IP载荷 TCP报文 TCP载荷 IP载荷(TCP报文) …

Golang编写客户端SDK,并开源发布包到GitHub,供其他项目import使用

目录 编写客户端SDK,并开源发布包到GitHub1. 创建 GitHub 仓库2. 构建项目,编写代码Go 代码示例:项目目录结构展示: 3. 提交代码到 GitHub仓库4. 发布版本5. 现在其他人可以引用使用你的模块包了 编写客户端SDK,并开源…

Vue项目案例-头条新闻

目录 1.项目介绍 1.1项目功能 1.2数据接口 1.3设计思路 2.创建项目并安装依赖 2.1创建步骤 2.2工程目录结构 2.3配置文件代码 3.App主组件开发 3.1设计思路 3.2对应代码 4.共通组件开发 4.1设计思路 4.2对应代码 5.头条新闻组件开发 5.1设计思路 5.2对应代码 …

Xcode打包ipa文件,查看app包内文件

1、Xcode发布ipa文件前,在info中打开如下两个选项,即可在手机上查看app包名文件夹下的文件及数据。

postman9.12.汉化版(附有下载链接)

想用英文版本的可以直接点击下载最新版本 这里直接付上9.12.2版本的下载链接,如果大家要下载别的版本,可以直接修改链接里面的版本号即可 ,下面是汉化包下载 链接:https://pan.baidu.com/s/1izK3HfqlfXJdq6KIYeJ2zw?pwdpetk 提…

【数据结构】2015统考真题 6

题目描述 【2015统考真题】求下面的带权图的最小(代价)生成树时,可能是Kruskal算法第2次选中但不是Prim算法(从v4开始)第2次选中的边是(C) A. (V1, V3) B. (V1, V4) C. (V2, V3) D. (V3, V4) …

【计算机组成 课程笔记】5.1 处理器的设计步骤

课程链接: 计算机组成_北京大学_中国大学MOOC(慕课) 5 - 1 - 501-处理器的设计步骤(14-49--)_哔哩哔哩_bilibili 处理器,或者说是CPU,是现代计算机中最为复杂的一个部件。不过先不要劝退,要设计一个简单但是…

如何检测勒索软件攻击

什么是勒索软件 勒索软件又称勒索病毒,是一种特殊的恶意软件,又被归类为“阻断访问式攻击”(denial-of-access attack),与其他病毒最大的不同在于攻击方法以及中毒方式。 攻击方法:攻击它采用技术手段限制…

若依 MyBatis改为MyBatis-Plus

主要内容:升级成mybatis-plus,代码生成也是mybatis-plus版本 跟着我一步一步来,就可完成升级! 检查:启动程序,先保证若依能启动 第一步:添加依赖 这里需要在两个地方添加,一个是最…

【C语言】——调试技巧

目录 ​编辑 ①前言 1.什么是Bug? 2.什么是调试? 2.1调试的基本步骤 2.2Release与Debug 3.常用快捷键 4.如何写出好的代码 4.1常见的coding技巧 👉assert() 👉const() const修饰指针: ①前言 调试是每个程序员都…

机器学习前沿:改进自身缺陷,满足新战略

前机械师( 来源) 一、说明 机器学习在人工智能历史上扮演重要角色,然而,存在问题也不少。为了适应新时代和新任务,不做出重大改进是不可能的,本篇就一些突出问题和改进做出讨论。以便读者掌握未来的思路和方向。 二、机…

【Lychee图床】本地电脑搭建私人图床,公网远程访问

文章目录 1.前言2. Lychee网站搭建2.1. Lychee下载和安装2.2 Lychee网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 图床作为图片集中存放的服务网站,可以看做是云存储的一部分,既可…