第四章:View的工作原理
4.1 ViewRoot和DecorView
ViewRoot对应于ViewRootImplement类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完成的.
在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联
View的绘制流程是从ViewRoot的performTraversals方法开始的,它经过measure,layout和draw三个过程来将一个View绘制出来
4.2 MeasureSpec
MeasureSpec参与了View的measure过程,在很大程度上决定了一个view的尺寸规格.
4.2.1 概念
MeasureSpec代表是一个32位int值,高2位代表SpecMode,低30位代表SpecSize,SpecMode是指测量模式,而SpecSize是指在某种测量模式下的规格大小.
SpecMode有三类:
- UNSPECIFIED:父容器不对View有任何限制,要多大给多大,一般用于系统内部,表示一个测量的状态
- EXACTLY:父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值.
- AT_MOST:父容器指定一个可用大小即SpecSize,View的大小不能大于这个值.
4.2.2 MeasureSpec和LayoutParams的对应关系
在View测量的时候,系统会将LayoutParams在父容器的约束下转换成对应的MeasureSpec,然后再根据这个MeasureSpec来确定View测量后的宽/高.
4.3 View的工作流程
View的工作流程主要是指measure,layout,draw这三大流程,即测量,布局和绘制,其中measure确定View的测量宽/高,layout确定View的最终宽高和四个顶点的位置,而draw则将View绘制到屏幕.
4.3.1 measure过程
1. View的measure过程
View的measure过程由其measure方法来完成,measure方法是一个final类型的方法,子类不能重写此方法,在View的measure方法中会去调用View的onMeasure方法
2. ViewGroup的measure过程
除了完成自己的measure过程之外,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个过程.
ViewGroup是一个抽象类,因此它没有重写View的onMeasure方法,但是提供了measureChildren的方法.
measureChild的思想就是取出子元素的LayoutParams,然后再通过getChildMeasureSpec来创建子元素的MeasureSpec,接着将MeasureSpec直接传递给View的measure方法进行测量.
如果它的布局中高度采用的是match_parent或者具体数值,那么它的测量过程和View一致,即高度为SpecSize;如果它的布局中高度采用的是wrap_content,那么它的高度是所有子元素所占用的高度综合,但是仍然不能超过它的父容器的剩余空间.
measure完成之后,可以通过getMeasuredWight/Height方法就可以正确的取到View的测量宽/高.
onWindowFocusChanged方法:View已经初始化完毕,宽/高已经准备好了,这个时候去获取宽/高
view.post(runnable)方法:通过post可以将一个runnable投递到消息队列的尾部,然后等待Looper调用次runnable的时候,View也已经初始化好了.
ViewTreeObserver:可以使用OnGlobalLayoutListener这个接口,当View树的状态发生改变或者View树内部的View的可见性发生改变,onGlobalLayout方法方法将被回调.
view.measure:通过手动对View进行measure来得到View的宽/高
4.3.2 layout过程
Layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,它在onLayout中会遍历所有的子元素并调用其layout方法,在layout方法中onLayout方法又会被调用.
layout方法确定View本身的位置,而onLayout方法则会确定所有子元素的位置
layout方法大致流程:首先会通过setFrame方法来设定View的四个顶点的位置,接着调用onLayout方法,用途是父容器确定子元素的位置,和onMeasure方法类似
4.3.3 draw过程
- 绘制背景background.draw(canvas)
- 绘制自己(onDraw)
- 绘制children(dispatchDraw)
- 绘制装饰(onDrawScrollBars)
4.4 自定义View
4.4.1 自定义View的分类
- 继承View重写onDraw方法:采用这种方式需要自己支持wrap_content并且padding也需要自己处理
- 继承ViewGroup派生特殊的Layout:需要核实地处理ViewGroup的测量,布局这两个过程,并同时处理子元素的测量和布局过程
- 继承特定的View(如TextView):扩展某种已有的View的功能
- 继承特定的ViewGroup(如LinearLayout):像几种view组合在一起,不需要自己处理ViewGroup的测量和布局这两个过程.
4.4.2 自定义View须知
- 让View支持wrap_content
- 如果有必要,让View支持padding:直接继承View的控件,如果不在draw方法中处理padding,那么padding属性是无法起作用的,另外,直接继承自ViewGroup的控件需要在onMeasure和onLayout中考虑padding和子元素的margin对其造成的影响.
- 尽量不要在View中使用Handler:view内部本身就提供了post系列的方法,完全可以替代Handler的作用
- View中如果有线程或者动画,需要及时停止:当包含次View的Activity退出或者当前View被remove时,view的onDetachedFromWindow方法会被调用,和此方法对应的是onAttachToWindow,当包含此View的Activity启动时,View的onAttachedToWindow方法会被调用.
- View带有滑动嵌套情形时,需要处理好滑动冲突.
4.4.3 自定义View
自定义属性:
第一步:在values目录下面创建自定义属性的XML(一般以attrs_开头的文件名)
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="CircleView">
<attr name="circle_color" format="color"/>//定义一个格式为"color"的属性
</declare-styleable>
</resources>
第二步:在View的构造方法中解析自定义属性的值并做相应处理.
public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypeArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
mColor = a.getColor(styleable.CircleView_circle_color, Color.RED);
a.recycle();
init();
}
加载自定义属性集合CircleView,接着解析CircleView属性集合中的circle_color属性
如果在使用时没有指定circle_color这个属性,那么就会选择红色作为默认的颜色值.
解析完成之后通过recycle方法来实现资源
第三步:在布局文件中使用自定义属性
<LinearLayout xmlns:android="http://schemes.android.com/apk/res/android"
xmlns:app="http://schemes.android.com/apk/res-auto"//必须在布局文件中添加schemas声明
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"> <com.example.CircleView
android:id="@+id/circleView1"
android:layout_height="wrap_content"
android:layout_height="100dp"
android:layout_margin="20dp"
app:circle_color="@color/light_green"
android:padding="20dp"
android:background="#00000"/> </LinearLayout>
其它的View继承也是基于这种思路,measure,layout,draw.
第四章:View的工作原理的更多相关文章
- Android艺术开发探索第四章——View的工作原理(下)
Android艺术开发探索第四章--View的工作原理(下) 我们上篇BB了这么多,这篇就多多少少要来点实战了,上篇主席叫我多点自己的理解,那我就多点真诚,少点套路了,老司机,开车吧! 我们这一篇就扯 ...
- Android艺术开发探索第四章——View的工作原理(上)
这章就比较好玩了,主要介绍一下View的工作原理,还有自定义View的实现方法,在Android中,View是一个很重要的角色,简单来说,View是Android中视觉的呈现,在界面上Android提 ...
- 《Android开发艺术探索》读书笔记 (4) 第4章 View的工作原理
本节和<Android群英传>中的第3章Android控件架构与自定义控件详解有关系,建议先阅读该章的总结 第4章 View的工作原理 4.1 初始ViewRoot和DecorView ( ...
- 四、View的工作原理
1.ViewRoot和DecorView ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot来完 ...
- 梳理源码中 View 的工作原理
欢迎Follow我的GitHub, 关注我的掘金. 在View的工作过程中, 执行三大流程完成显示, 测量(measure)流程, 布局(layout)流程, 绘制(draw)流程. 从perform ...
- Android学习笔记View的工作原理
自定义View,也可以称为自定义控件,通过自定义View可以使得控件实现各种定制的效果. 实现自定义View,需要掌握View的底层工作原理,比如View的测量过程.布局流程以及绘制流程,除此之外,还 ...
- View的工作原理(一) 总览View的工作流程
View的工作原理(一) 总览View的工作流程 学习自 <Android开发艺术探索> 简书博主-丶蓝天白云梦 Overview 从本章开始,开始学习View的工作原理,包括View的 ...
- Android之view的工作原理2
学习内容 View的底层工作原理,比如View的测量流程.布局流程以及绘制流程:以及常见的View回调方法:熟悉掌握前面的知识后,自定义View的时候也会更加的得心应手. 4.1 初识ViewRoot ...
- Android 中View的工作原理
Android中的View在Android的知识体系中扮演着重要的角色.简单来说,View就是Android在视觉的体现.我们所展现的页面就是Android提供的GUI库中控件的组合.但是当要求不能满 ...
随机推荐
- 工欲善其事,必先利其器 -- Mac 软件推荐(序)
背景 工欲善其事,必先利其器.后面我将陆陆续续推荐一些软件利器帮助大家提高效率(主要针对 Mac 电脑). 如果你在使用 Mac 电脑,并且没有如某些人那样安装并使用 Windows 系统,那么你可 ...
- 小师妹学JVM之:JDK14中JVM的性能优化
目录 简介 String压缩 分层编译(Tiered Compilation) Code Cache分层 新的JIT编译器Graal 前置编译 压缩对象指针 Zero-Based 压缩指针 Escap ...
- Python数据结构01 线性结构
栈 实现 后进先出的结构,主要有如下操作 *Stack() *push(item) *pop() *peek() *isEmpty() *size() class Stack(): def __ini ...
- Jenkins入门-环境搭建(1)-转
因为Jenkins的环境搭建比较简单,本来不想来介绍,但是发现有些入门小朋友,从各种网站上下载的各种安装包来搭建,最后导致出现了各种千奇百怪的问题,介于这种情况下我决定还是来写一下Jenkins的环境 ...
- HashMap的基本使用
常用方法 首先,我们应该知道HashMap类实现了Map接口,所以实现了Map常用的一些方法. (1) 插入键值对数据 public V put(K key, V value) (2)根据键值获取键值 ...
- 使用训练好的modle,做些有用的事(各层数据可视化)
---恢复内容开始--- 1. 加载必要的库: 2. 设置当前目录,判断模型是否训练好: 3. 利用提前训练好的模型,设置测试网络: 4. 加载测试图片,并显示: 5. 编写一个函数,将二进制的均值转 ...
- 计算区间 1 到 n 的所有整数中,数字 x(0 ≤ x ≤ 9) 共出现了多少次?
#include<iostream> using namespace std; int main() { long long start, end , i, check, b, c, cn ...
- 集群搭建完成简要测试集群(性能)带宽与IOPS
集群搭建好之后网络,raid卡策略,磁盘都会影响集群的性能.为了避免因上述问题使得集群的性能受到影响,我们依次进行测试,最后得到基本的集群性能. 网络 首先是网络,ceph集群一大堆让人摸不着头脑的问 ...
- JavaScript图形实例:Koch曲线
Koch曲线的构造过程是:取一条长度为L0的直线段,将其三等分,保留两端的线段,将中间的一段改换成夹角为60度的两个等长直线:再将长度为L0/3的4个直线段分别进行三等分,并将它们中间的一段均改换成夹 ...
- Oracle Solaris 11.4安装桌面/gdb
文章目录 1. 说明 2. 挂载镜像 3. 安装桌面 4. 安装gdb 5. 重启OS 1. 说明 该文承接上文Solaris 11.4安装,映像包管理系统(IPS)搭建. Solaris 11.4的 ...