内容简介:理解 View 的工作原理,熟悉自定义 View 的各种套路。本章节配套源码
理解 View 的工作原理,熟悉自定义 View 的各种套路。
1. ViewRoot 和 DecorView
- ViewRoot 对应于 ViewRootImpl 类,它是连接 WindowManager 和DecorView 的纽带。
- View 的绘制流程是从 ViewRoot 的
performtraversals方法开始的:
- measure 的过程决定了 View 的宽高,完成后可以通过 getMeasuredWidth 和 getMeasuredHeight 获取。
- layout 的过程决定了 View 的四个顶点的坐标和实际宽高,完成后可以通过
getTop、getBottom、getLeft和getRight获取。 - draw 的过程决定了 View 的显示,完成后才能呈现在屏幕上。
- 在 Activity 中通过
setContentView的布局可以通过以下方式获取到:ViewGroup content = findViewById(android.R.id.content);
2. MeasureSpec
- MeasureSpec 和父容器决定了 View 的尺寸规格。
-
MeasureSpec 是一个 32 位的 int 值,高 2 位代表 SpecMode ,低 30 位代表 SpecSize 。
> int mode = MeasureSpec.getMode(spec); > int size = MeasureSpec.getSize(spec); >
-
SpecMode 有三类:
- UNSPECIFIED :父容器不对 View 有任何限制,要多大给多大。
- EXACTLY :父容器已经检测出 View 所需的精确代销,这时 View 的最终大小就是 SpecSize 的值,它对应于 LayoutParams 中的 match_parent 或具体大小数值。
- AT_MOST :父容器指定了一个大小 SpecSize,View 不能大于这个值,最终大小取决于 View 的具体实现,它对应于 LayoutParams 中的 wrap_content。
- 我们在给 View 设置 LayoutParams 后,系统会在父容器的约束下将 LayoutParams 转换成对应的 MeasureSpec。
- 顶级 DecorView,其 MeasureSpec 由窗口尺寸和自身 LayoutParams 决定。
- 普通 View,其 MeasureSpec 由父容器的 MeasureSpec 和自身 LayoutParams 决定。
- 普通 View 的 MeasureSpec 创建规则:
| childLayoutParams \ parentSpecMode | EXACTLY | AT_MOST | UNSPECIFIED |
|---|---|---|---|
| dp/px | EXACTLY childSize |
EXACTLY childSize |
EXACTLY childSize |
| match_parent | EXACTLY parentSize |
AT_MOST parentSize |
UNSPECIFIED 0 |
| wrap_content | AT_MOST parentSize |
AT_MOST parentSize |
UNSPECIFIED 0 |
3. View 的工作流程
3.1 measure 过程
- 分两种情况,如果是一个原始 View,通过
measure方法就完成了测量过程;如果是 ViewGroup,除了完成自己的测量,还要遍历子元素的measure方法。 - 直接继承 View 的自定义控件需要重写
onMeasure方法并设置 wrap_content 时的自身大小,否则在布局中使用 wrap_content 时就相当于使用 match_parent; - ViewGroup 是一个抽象类,并没有定义其具体的测量过程,但它提供了一个
measureChildren(int widthMeasureSpec, int heightMeasureSpec)的方法来测量子元素,该方法里循环调用measureChild(child, widthMeasureSpec, heightMeasureSpec)方法,measureChild的思想就是取出元素的 LayoutParams,然后通过getChildMeasureSpec方法创建子元素的 MeasureSpec,最后将 MeasureSpec 传递给 View 的measure方法来进行测量。 - 简化版的流程图如下:
- 由于在一些极端情况下,系统要在多次 measure 后才能确定测量的结果,所以在 onMeasure 中拿到的宽高可能不准确,推荐在 onLayout 中获取。
-
准确获取 View 宽高的四种方式:
- Activity/View#onWindowFocusChanged
- view.post(runnable)
-
ViewTreeObserver
... ViewTreeObserver observer = view.getViewTreeObserver(); observer.addOnGlobalLayoutListener ...
-
view.measure(int widthMeasureSpec, int heightMeasureSpec)
3.2 layout 过程
- View 的 onLayout 方法为空实现,而 ViewGroup 继承自 View 也没有实现该方法,所以 onLayout 具体实现由父容器的特性决定,比如 LinearLayout。
- 简易的流程图如下:
- 在 View 的默认实现中,View 的测量宽高和最终宽高是相等的,只不过测量宽高形成于 measure 过程,而最终宽高形成于 layout 过程,两者赋值时机不同。
3.3 draw 过程
- draw 的绘制过程遵循如下几步:
background.draw(canvas) onDraw dispatchDraw onDrawScrollBars
- ViewGroup 默认启用绘制优化标记位,如果 ViewGroup 需要通过 onDraw 来绘制内容,我们可以通过
setWillNotDraw(false);来关闭该标记位。
4. 自定义 View
- 自定义 View 大体可以分为四类:
- 继承 View 重写 onDraw 方法
- 继承 ViewGroup 派生特殊的 Layout
- 继承特定的 View(比如 TextView)
- 继承特定的 ViewGroup(比如 LinearLayout)
- 自定义 View 须知:
post View#onDetachedFromWindow
本章节配套源码 戳我
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Data Mining
Bing Liu / Springer / 2011-6-26 / CAD 61.50
Web mining aims to discover useful information and knowledge from Web hyperlinks, page contents, and usage data. Although Web mining uses many conventional data mining techniques, it is not purely an ......一起来看看 《Web Data Mining》 这本书的介绍吧!