##前言

算是第一篇正式的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. [Android FrameWork 6.0源码学习] View的重绘过程之Draw

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

  3. [Android FrameWork 6.0源码学习] LayoutInflater 类分析

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

  4. [Android FrameWork 6.0源码学习] ViewGroup的addView函数分析

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

  5. [Android FrameWork 6.0源码学习] View的重绘过程

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

  6. [Android FrameWork 6.0源码学习] View的重绘过程之Layout

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

  7. [Android FrameWork 6.0源码学习] View的重绘ViewRootImpl的setView方法

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

  8. [Android FrameWork 6.0源码学习] Window窗口类分析

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

  9. [Android阅读代码]android-async-http源码学习一

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

随机推荐

  1. 响铃:蜗牛读书“文”、网易云信“武”:游戏之外网易的AB面

    文|曾响铃来源|科技向令说(xiangling0815) 2019年开年,网易又"搞事情"了. 近日,网易集团旗下网易云信.网易七鱼主办的"网易MCtalk泛娱乐创新峰会 ...

  2. Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

    1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...

  3. 【javascript/PHP】当一个JavaScripter初次进入PHP的世界,他将看到这样的风景

     本文将从以下11点介绍javascript和PHP在基础语法和基本操作上的异同: 1.数据类型的异同 2.常量和变量的定义的不同,字符串连接运算符不同 3.对象的创建方法的不同 4.PHP与JS在变 ...

  4. C#实时检测端口占用情况

    在TCP/IP协议中,服务端需要去监听客户端的端口,开始监听,我们需要检测使用的端口是否被占用,获取系统当前使用的所有端口号,用此端口进行匹配即可. 代码如下 internal static Bool ...

  5. 通过Yum快速部署LAMP与LNMP

    LAMP动态网站部署架构是由一套 Linux+Apache+MySQL+PHP 组成的动态网站系统解决方案. LNMP动态网站部署架构是由一套 Linux+Nginx+MySQL+PHP 组成的动态网 ...

  6. Python 私有变量中两个下划线 _ _item 与 一个下划线的区别 _item

    python中没有常量的说法, 但是可以通过元组实现一个常量 在python的私有变量中, 存在两个下划线 _ _item 与一个下划线 _item 的区别 前面带两个下划线的私有变量: 只能在本类中 ...

  7. ThreadLocal的练习代码

    场景: 有三个小孩儿,买了一个变形金刚玩具(Transformer).... 三个小孩都争着玩这个玩具....没有一个人可以玩... 第一种方式:每个人各玩一会.... 第二种方式:再买两个玩具,一个 ...

  8. C# 多线程六之Task(任务)二

    前面介绍了Task的由来,以及简单的使用,包括开启任务,处理任务的超时.异常.取消.以及如果获取任务的返回值,在回去返回值之后,立即唤起新的线程处理返回值.且如果前面的任务发生异常,唤起任务如果有效的 ...

  9. 为什么研发团队不适合量化KPI的绩效考核?

    研发团队(如果不是外包,不是机械性的活动)如果进行的是creative的有创造性的智力活动,那么应该不适合用量化KPI的绩效考核和激励,不应该用工时.bug数(难度大的bug可能多,测试人员可能没有经 ...

  10. Android开发艺术探索学习笔记(六)

    第六章 Android的Drawable  Drawable的优点:使用简单,比自定义view的成本要低:非图片类型的Drawable占用空间小,有利于减小APK安装包的大小. 6.1Drawable ...