博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
39、自定义控件(四)-- View源码分析
阅读量:6199 次
发布时间:2019-06-21

本文共 2715 字,大约阅读时间需要 9 分钟。

一、View源码分析

ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程全是通过ViewRoot来完成的。

在ActivityThread中,当Activity对象被创建后,会将DectorView添加到Window中,同时会创建ViewRootImpl对象,并将

ViewRootImpl对象和decorView建立关联,这个过程我们可以参看源码:

root = new ViewRootImpl(view.getContext(),display);root.setView(view,wparams,panelparentView);

View的绘制流程是从ViewRoot的performTeaversals方法开始的,它经过measure、layout、draw三个过程才能最终将一个View绘制出来。

其中measure用来测量View的宽和高,layout用来确定View在父容器中放置的位置,而draw负责将View绘制在屏幕上。

针对performTraversals的大致流程:

如图所示,performTraversals会依次调用performMeasure、performLayout和performDraw三个方法,分别完成顶级View的measure、layout和draw三大流程。

PperformMeasure会调用measure方法,measure方法又会调用onMeasure,其中onMeasure又会调用所有子元素的measure方法完成测量。

同理,performLayout和performDraw也是如此。

DecorView是顶级View,它其实是一个FrameLayout,View层的事件都先经过DecorView,然后才传递给我们的View。

1.1、Measure的原理

measure过程中,如果是View,则通过measure方法即可完成测量过程,如果是ViewGroup,则需要完成自己的测量过程外,

还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个流程。

1、View的measure过程

  View的measure过程由其measure方法完成,measure方法是被final修饰的方法,不能重写。在View的measure方法中会去调用View的onMeasure方法,

因此只需要看onMeasure方法的实现即可:

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

setMeasureDimension方法会设置View的宽和高来代表测量的结束,因此我们只需要看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;}

对于我们来说只需要看AT_MOST和EXACTLY两种情况,其实getDefaultSize返回的大小就是measureSpec中的specSize,它就是View测量后的大小。

而UNSPECIFIED这种情况一般用于系统内部的测量过程,在这种情况下,View的大小为getDefault的第一个参数size,即宽和高分别是

getSuggestedMinimumWidth和getSuggestedMinimumHeught这两个方法的返回值。

protected int getSuggestedMinimumHeight() {    return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());}protected int getSuggestedMinimumWidth() {    return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());}

可以看出,如果在没有指定背景的情况下,宽度和高度分别是mMinWidth和mMinHeight,如果不指定该属性,则默认为0.

如果指定背景的情况下,宽度和高度分别是max(mMinHeight, mBackground.getMinimumHeight())和max(mMinWidth, mBackground.getMinimumWidth())

那么我来看看mBackground.getMinimumWidth()方法:

public int getMinimumWidth() {    final int intrinsicWidth = getIntrinsicWidth();    return intrinsicWidth > 0 ? intrinsicWidth : 0;}

可以看出,在Drawable有原始宽度的情况下,该方法返回的就是Drawable的原始宽度,当然高度也是如此。

转载于:https://www.cnblogs.com/pengjingya/p/5510714.html

你可能感兴趣的文章
现代 JavaScript 函数库 usuallyjs 的安装和使用
查看>>
HTTP 简介
查看>>
实习面试笔记
查看>>
不同工具查看代码分支diff的差异
查看>>
你应该知道的Redis过期键和过期策略
查看>>
一文让你明白Redis主从同步
查看>>
半小时撸一个抽奖程序
查看>>
redis数据结构实现--简单动态字符串
查看>>
Flask内置命令行工具—CLI
查看>>
[LeetCode] 312. Burst Balloons
查看>>
初识 jquery.simulate.js 模拟键盘事件
查看>>
7年开发详谈塞班之死,iOS开发寒冬将至,谁不是在苦苦坚持?
查看>>
ELF格式探析之三:sections
查看>>
Vue事件处理
查看>>
深入理解浏览器的缓存机制
查看>>
git中项目管理
查看>>
预告:JavaScript模块全览
查看>>
Julia接口:Iteration接口-迭代
查看>>
Webpack4干货分享:第一部分,入口、输入和ES6模块
查看>>
“大数据+”实践:数据平台的设计与搭建
查看>>