View表示了用户界面的基本构建模块。
- 一个View占用了屏幕上的一个矩形区域并且负责界面绘制和事件处理。手机屏幕上所有看得见摸得着的都是View。
- Activity是四大组件中唯一一个用来和用户进行交互的组件。可以说Activity就是android的视图层。
- 如果再细化,Activity相当于视图层中的控制层,是用来控制和管理View的,真正用来显示和处理事件的实际上是View。
- 每个Activity内部都有一个Window对象, Window对象包含了一个DecorView(实际上就是FrameLayout),我们通过setContentView给Activity设置显示的View实际上都是加到了DecorView中。
- android提供了种类丰富的View来应对各种需求,例如提供文字显示的TextView,提供点击事件的Button,提供图片显示的ImageView,还有各种布局文件,例如Relativilayout,Linearlayout等等。他们都是继承自View。
- view被展示到界面上需要经过3个步骤
-
- 需要花多大 measure ----> onMeasure---> setMeasuredDimension
- 画在什么地方 layout --- setFrame --- onLayout
- 怎么画 draw --- > onDraw ---> dispatchDraw
ViewGroup继承自View,并实现了两个接口ViewParent和ViewManager。
- ViewManager提供了三个抽象方法addView,removeView,updateViewLayout。用来添加、删除、更新布局。
- ViewParent主要提供了一系列操作子View的方法例如焦点的切换,显示区域的控制等等。
- 实际上所有的事情View都能做,包括显示复杂的界面,我们只需要设计一个复杂的View即可。例如短信通知的icon,一个可以显示图片又可以显示文字的View,我们后期学习了View的draw方法后,可以轻松的设计一个View来达到这个效果,但是这样不仅复杂,而且重用性较差,还会因为一点小改动而重复的创造轮子,这显然不符合程序员偷懒的原则,所以我们可以完全把ImageView和TextView组合到一起就可以了,这个时候我们就需要一个容器,ViewGroup,来装这两个View。
- ViewGroup和View最大的不同是可以组合多个View,那么多个View在一起,该如何摆放,这就是ViewGroup需要解决的问题。
- 我们看到的界面,都是以一个ViewGroup作为根View,通过往ViewGroup中添加子View(可以是View,也可以是ViewGroup),来组合出各具特色的界面。
- 这种从根到叶的组合方式,我们可以看做成一个View树。(类似于XML),而View的显示和事件处理,都是依赖于这个View树。
- 绘制和事件处理的起始点,都是从根View开始一级一级的往下传递。我们从任意一层发起绘制,都将反馈到根View,然后再从上往下传递。
- 之前我们说过根View就是Window中的DecorView,也就是一个FrameLayout。
View事件分发
- 返回true,说明可以响应down事件和up事件
- 返回false,说明只会相应down事件
View的测量/布局/绘制过程
- Measure测量一个View的大小
- Layout摆放一个View的位置
- Draw画出View的显示内容
- 其中measure和layout方法都是final的,无法重写,虽然draw不是final的,但是也不建议重写该方法。
- 这三个方法都已经写好了View的逻辑,如果我们想实现自身的逻辑,而又不破坏View的工作流程,可以重写onMeasure、onLayout、onDraw方法。
- 通过调用requestLayout/requestFocus都将发起一个View树的测量。测量完毕后会进行布局,布局完毕后就会绘制。
- 如果View的大小没有发生改变,布局也没有变化,只是显示的内容发生了变化,则可以通过invalidate来请求绘制,此时将不会测量和布局,直接从绘制开始。
- View中有一个私有int变量mPrivateFlags,用于保存View的状态,int型32位,通过0/1可以保存32个状态的true或者false,采用这种方式可以有效的减少内存占用,提高运算效率。
- 当某一个View发起了测量请求时,将会把mPrivateFlags中的某一位从0变为1,同时请求父View,父View也会把自身的该值从0变为1,同时也将会把其他子View的值从0变为1。这样一层一层传递,最终传到到DecorView,DecorView的父View是ViewRoot,所以最终都将由ViewRoot来进行处理。
- ViewRoot收到请求后,将会从上至下开始遍历,检查标记,只要有相对应的标记就执行测量/布局/绘制
- FORCE_LAYOUT 请求绘制,将从measure开始,,并增加LAYOUT_REQUIRED标记
- 持有LAYOUT_REQUIRED标记的View将会被执行layout,完毕后会去掉LAYOUT_REQUIRED和FORCE_LAYOUT
- DRAWN带有该标签的将不会被draw,注意,这和上面两个不一致,当draw完毕后会加上该标签,当没有该标签才会被draw。
- 还有一些其他的标记位。