Android-View的绘制源码学习总结

时间:2022-09-12 19:41:28

##前言

算是第一篇正式的github博文,回顾了一下之前看过的view源码解析,做一个对目前为止View学习小的总结。

我觉得对于源码的解析和学习,把所有流程记下来意义并不是很大,最关键的是:

1.知道基本作用和用法
2.大概了解整个流程和实现方法
3.了解里面可扩展的地方在哪,更灵活地使用
4.整个源码设计和细节有没有什么亮点值得参考和学习
5.源码设计的思路

这也是写这篇文章的目的所在。

##加载布局

####LayoutInflater

http://www.cnblogs.com/qlky/p/5674975.html

- **作用**

LayoutInflater是用来加载布局的,我们最简单的代码:

```
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainlayout);
}
```

中的setContentView就是用LayoutInflater实现的

- **用法**

可以用来动态加载布局
```
LayoutInflater layoutInflater = LayoutInflater.from(this);
View buttonlayout = layoutInflater.inflate(R.layout.button_layout,null);
mainlayout.addView(buttonlayout);
```

- **原理**

inflate是用pull来解析xml格式的,其中调用了createViewFromTag()这个方法,并把节点名和参数传了进去。看到这个方法名,我们就应该能猜到,它是用于根据节点名来创建View对象的。
确实如此,在createViewFromTag()方法的内部又会去调用createView()方法,然后使用反射的方式创建出View的实例并返回。

对于布局子元素会用rinflate()去循环实现。

- **拓展**

从源码可以知道

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)的第三个参数attachToRoot

1. 如果root为null,attachToRoot将失去作用,设置任何值都没有意义。

2. 如果root不为null,attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。

3. 如果root不为null,attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。

4. 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。

所有控件的layout_width等属性,都要有一个父布局才能生效,因为这是用来设置view在布局中的大小,而不是view的大小,所以叫layout_width,不是width。

而LinearLayout的layout_width有效是因为,在setContentView()方法中,Android会自动在布局文件的最外层再嵌套一个FrameLayout,id为content

所以叫setContentView(),其实这个方法也是用Layoutlnflater()实现的

##视图绘制

http://www.cnblogs.com/qlky/p/5676578.html
http://www.jianshu.com/p/5a71014e7b1b

View的绘制要经过三个过程,measure,layout和draw

####Measure

- **作用**

测量view及其子view的大小

- **原理**

MeasureSpec:由父View的MeasureSpec和子View的LayoutParams通过简单的计算得出一个针对子View的测量要求

计算原理很简单:
如果我们在xml 的layout_width或者layout_height 把值都写死,那么上述的测量完全就不需要了,之所以要上面的这步测量,是因为 match_parent 就是充满父容器,wrap_content 就是自己多大就多大, 我们写代码的时候特别爽,我们编码方便的时候,google就要帮我们计算你match_parent的时候是多大,wrap_content的是多大,这个计算过程,就是计算出来的父View的MeasureSpec不断往子View传递,结合子View的LayoutParams 一起再算出子View的MeasureSpec,然后继续传给子View,不断计算每个View的MeasureSpec,子View有了MeasureSpec才能更测量自己和自己的子View。

几种情况:
1.父view MeasureSpec = exactly 大小确定,子view:
match_parent:EXACTLY
warp_content:AT MOST
确定值

2.父view MeasureSpec = exactly 大小不确定,子view:
match_parent:AT MOST
warp_content:AT MOST
确定值

View的测量主要在onMeasure方法里

对于View默认是测量很简单,大部分情况就是拿计算出来的MeasureSpec的size 当做最终测量的大小。而对于其他的一些View的派生类,如TextView、Button、ImageView等,它们的onMeasure方法系统了都做了重写,不会这么简单直接拿 MeasureSpec 的size来当大小,而去会先去测量字符或者图片的高度等,然后拿到View本身content这个高度(字符高度等),如果MeasureSpec是AT_MOST,而且View本身content的高度不超出MeasureSpec的size,那么可以直接用View本身content的高度(字符高度等),而不是像View.java 直接用MeasureSpec的size做为View的大小。

整个View的Root是DecorView,那么View的绘制是从哪里开始的呢,我们知道每个Activity 均会创建一个 PhoneWindow对象,是Activity和整个View系统交互的接口,每个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,对于Activity来说,ViewRootImpl是连接WindowManager和DecorView的纽带,绘制的入口是由ViewRootImpl的performTraversals方法来发起Measure,Layout,Draw等流程的。

具体流程: DecorView -> ... -> content -> LinearLayout/... -> TextView/...
得到每层的MeasureSpec,最后在底层得到大小。然后再往上得到父view的大小

- **拓展**

对于onMeasure方法的重写

####Layout

- **作用**

确定view在布局中的位置。ViewRoot的performTraversals()方法会在measure结束后继续执行,并调用View的layout()方法来执行此过程,如下所示:

```
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
```

- **原理**

首先会调用setFrame()方法来判断视图的大小是否发生过变化,以确定有没有必要对当前的视图进行重绘,同时还会在这里把传递过来的四个参数分别赋值给mLeft、mTop、mRight和mBottom这几个变量。
接下来会调用onLayout()方法。
View中的onLayout()方法是一个空方法,因为onLayout()过程是为了确定视图在布局中所在的位置,而这个操作应该是由布局来完成的,即父视图决定子视图的显示位置。
ViewGroup中的onLayout()方法是一个抽象方法,子类必须重载onLayout函数,而重载onLayout的目的就是安排其children在父视图的具体位置

- **拓展**

重载onLayout函数

####Draw

- **作用**
绘制view

- **原理**

分为六步,其中第二步和第五步在一般情况下很少用到

第一步:背景绘制

第三步,对View的内容进行绘制
onDraw(canvas) 方法是view用来draw 自己的,具体如何绘制,颜色线条什么样式就需要子View自己去实现,View.java 的onDraw(canvas) 是空实现,ViewGroup 也没有实现,每个View的内容是各不相同的,所以需要由子类去实现具体逻辑。

第四步 对当前View的所有子View进行绘制
dispatchDraw(canvas) 方法是用来绘制子View的,View.java 的dispatchDraw()方法是一个空方法,因为View没有子View,不需要实现dispatchDraw ()方法,ViewGroup就不一样了,它实现了dispatchDraw ()方法,就是遍历子View然后drawChild(),drawChild()方法实际调用的是子View.draw()方法,ViewGroup类已经为我们实现绘制子View的默认过程,这个实现基本能满足大部分需求,所以ViewGroup类的子类(LinearLayout,FrameLayout)也基本没有去重写dispatchDraw方法,我们在实现自定义控件,除非比较特别,不然一般也不需要去重写它

第6步 对View的滚动条进行绘制

- **拓展**

重写onDraw方法

Android-View的绘制源码学习总结的更多相关文章

  1. [Android FrameWork 6.0源码学习] View的重绘过程之WindowManager的addView方法

    博客首页:http://www.cnblogs.com/kezhuang/p/关于Activity的contentView的构建过程,我在我的博客中已经分析过了,不了解的可以去看一下<[Andr ...

  2. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; View的重绘过程之Draw

    View绘制的三部曲,测量,布局,绘画现在我们分析绘画部分测量和布局 在前两篇文章中已经分析过了.不了解的可以去我的博客里找一下 下面进入正题,开始分析调用以及函数原理 private void pe ...

  3. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; LayoutInflater 类分析

    LayoutInflater是用来解析XML布局文件,然后生成对象的ViewTree的工具类.是这个工具类的存在,才能让我们写起Layout来那么省劲. 我们接下来进去刨析,看看里边的奥秘 //调用i ...

  4. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; ViewGroup的addView函数分析

    Android中整个的View的组装是采用组合模式. ViewGroup就相当与树根,各种Layout就相当于枝干,各种子View,就相当于树叶. 至于View类.我们就当它是个种子吧.哈哈! Vie ...

  5. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; View的重绘过程

    View绘制的三部曲,  测量,布局,绘画今天我们分析测量过程 view的测量是从ViewRootImpl发起的,View需要重绘,都是发送请求给ViewRootImpl,然后他组织重绘在重绘的过程中 ...

  6. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; View的重绘过程之Layout

    View绘制的三部曲,测量,布局,绘画现在我们分析布局部分测量部分在上篇文章中已经分析过了.不了解的可以去我的博客里找一下 View的布局和测量一样,都是从ViewRootImpl中发起,ViewRo ...

  7. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; View的重绘ViewRootImpl的setView方法

    博客首页:http://www.cnblogs.com/kezhuang/p/ 本篇文章来分析一下WindowManager的后续工作,也就是ViewRootImpl的setView函数的工作 /i* ...

  8. &lbrack;Android FrameWork 6&period;0源码学习&rsqb; Window窗口类分析

    了解这一章节,需要先了解LayoutInflater这个工具类,我以前分析过:http://www.cnblogs.com/kezhuang/p/6978783.html Window是Activit ...

  9. &lbrack;Android阅读代码&rsqb;android-async-http源码学习一

    android-async-http 下载地址 一个比较常用的Http请求库,基于org.apache.http对http操作进行封装. 特点: 1.每一个HTTP请求发生在UI线程之外,Client ...

随机推荐

  1. 过目不忘JS正则表达式

    正则表达式,有木有人像我一样,学了好几遍却还是很懵圈,学的时候老明白了,学完了忘光了.好吧,其实还是练的不够,所谓温故而知新,可以为师矣,今天就随我来复习一下这傲娇的正则表达式吧. 为啥要有正则表达式 ...

  2. js常见数字处理整理

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  3. Linux&amp&semi;shell 之Shell命令进阶

    写在前面:案例.常用.归类.解释说明.(By Jim) 监控程序a.进程查看ps -ef(-e表示系统上运行的所有进程,-f用于扩展输出一些有用的信息列.)ps -efH(-H参数可以将进程组织为分层 ...

  4. &num;&num;DAY4 事件的基本概念、触摸的基本概念、响应者链、手势

    ##DAY4  事件的基本概念.触摸的基本概念.响应者链.手势 #pragma mark ———————事件的基本概念 ——————————— 事件的基本概念: 1)事件是当用户的手指触击屏幕及在屏幕 ...

  5. python2&period;6升级到2&period;7

    开发部需要使用python2.7,由于公网的环境python版本都是系统自带的,版本是2.6,需要升级,最好是通过RPM升级. Linux系统:CentOS CentOS 6.4升级Python后yu ...

  6. 源于《Unity官方实例教程 &OpenCurlyDoubleQuote;Space Shooter”》思路分析及相应扩展

    教程来源于:Unity官方实例教程 Space Shooter(一)-(五)       http://www.jianshu.com/p/8cc3a2109d3b 一.经验总结 教程中步骤清晰,并且 ...

  7. Windows下配置Git多账号github码云

    Windows下配置Git多账号github码云 1.配置了全局用户名和邮箱 $ git config --global user.email "你的邮箱" $ git confi ...

  8. 【原创】大数据基础之Spark(4)RDD原理及代码解析

    一 简介 spark核心是RDD,官方文档地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html#resilient-di ...

  9. element-ui Select 清空model,页面没有清空选中项的问题

    业务场景: 在dialog 每次打开时, 选择应用程序要初始化为空. 最初的做法为: 监听dialog的show状态,当show为false时,设置selectApp为空这样写时,虽然selectAp ...

  10. Installshield 打包安装程序时写入注册表,及运行bat文件

    一.写入注册表 1. 打开project assistant –> Project Registry 可以像注册表里一样操作,其中[INSTALLDIR]是指的安装路径   二. 运行bat文件 ...