View 的工作原理

栏目: IOS · Android · 发布时间: 6年前

内容简介:理解 View 的工作原理,熟悉自定义 View 的各种套路。本章节配套源码

理解 View 的工作原理,熟悉自定义 View 的各种套路。

1. ViewRoot 和 DecorView

  1. ViewRoot 对应于 ViewRootImpl 类,它是连接 WindowManager 和DecorView 的纽带。
  2. View 的绘制流程是从 ViewRoot 的 performtraversals 方法开始的:
    View 的工作原理
  3. measure 的过程决定了 View 的宽高,完成后可以通过 getMeasuredWidth 和 getMeasuredHeight 获取。
  4. layout 的过程决定了 View 的四个顶点的坐标和实际宽高,完成后可以通过 getTopgetBottomgetLeftgetRight 获取。
  5. draw 的过程决定了 View 的显示,完成后才能呈现在屏幕上。
  6. 在 Activity 中通过 setContentView 的布局可以通过以下方式获取到:
    ViewGroup content = findViewById(android.R.id.content);
    

2. MeasureSpec

  1. MeasureSpec 和父容器决定了 View 的尺寸规格。
  2. MeasureSpec 是一个 32 位的 int 值,高 2 位代表 SpecMode ,低 30 位代表 SpecSize

    > int mode = MeasureSpec.getMode(spec);
    > int size = MeasureSpec.getSize(spec);
    >
    
  3. SpecMode 有三类:

    • UNSPECIFIED :父容器不对 View 有任何限制,要多大给多大。
    • EXACTLY :父容器已经检测出 View 所需的精确代销,这时 View 的最终大小就是 SpecSize 的值,它对应于 LayoutParams 中的 match_parent 或具体大小数值。
    • AT_MOST :父容器指定了一个大小 SpecSize,View 不能大于这个值,最终大小取决于 View 的具体实现,它对应于 LayoutParams 中的 wrap_content。
  4. 我们在给 View 设置 LayoutParams 后,系统会在父容器的约束下将 LayoutParams 转换成对应的 MeasureSpec。
    • 顶级 DecorView,其 MeasureSpec 由窗口尺寸和自身 LayoutParams 决定。
    • 普通 View,其 MeasureSpec 由父容器的 MeasureSpec 和自身 LayoutParams 决定。
  5. 普通 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 过程

  1. 分两种情况,如果是一个原始 View,通过 measure 方法就完成了测量过程;如果是 ViewGroup,除了完成自己的测量,还要遍历子元素的 measure 方法。
  2. 直接继承 View 的自定义控件需要重写 onMeasure 方法并设置 wrap_content 时的自身大小,否则在布局中使用 wrap_content 时就相当于使用 match_parent;
  3. ViewGroup 是一个抽象类,并没有定义其具体的测量过程,但它提供了一个 measureChildren(int widthMeasureSpec, int heightMeasureSpec) 的方法来测量子元素,该方法里循环调用 measureChild(child, widthMeasureSpec, heightMeasureSpec) 方法, measureChild 的思想就是取出元素的 LayoutParams,然后通过 getChildMeasureSpec 方法创建子元素的 MeasureSpec,最后将 MeasureSpec 传递给 View 的 measure 方法来进行测量。
  4. 简化版的流程图如下:
    View 的工作原理
  5. 由于在一些极端情况下,系统要在多次 measure 后才能确定测量的结果,所以在 onMeasure 中拿到的宽高可能不准确,推荐在 onLayout 中获取。
  6. 准确获取 View 宽高的四种方式:

    • Activity/View#onWindowFocusChanged
    • view.post(runnable)
    • ViewTreeObserver

      ...
      ViewTreeObserver observer = view.getViewTreeObserver();
      observer.addOnGlobalLayoutListener
      ...
      
    • view.measure(int widthMeasureSpec, int heightMeasureSpec)

3.2 layout 过程

  1. View 的 onLayout 方法为空实现,而 ViewGroup 继承自 View 也没有实现该方法,所以 onLayout 具体实现由父容器的特性决定,比如 LinearLayout。
  2. 简易的流程图如下:
    View 的工作原理
  3. 在 View 的默认实现中,View 的测量宽高和最终宽高是相等的,只不过测量宽高形成于 measure 过程,而最终宽高形成于 layout 过程,两者赋值时机不同。

3.3 draw 过程

  1. draw 的绘制过程遵循如下几步:
    background.draw(canvas)
    onDraw
    dispatchDraw
    onDrawScrollBars
    
  2. ViewGroup 默认启用绘制优化标记位,如果 ViewGroup 需要通过 onDraw 来绘制内容,我们可以通过 setWillNotDraw(false); 来关闭该标记位。

4. 自定义 View

  1. 自定义 View 大体可以分为四类:
    1. 继承 View 重写 onDraw 方法
    2. 继承 ViewGroup 派生特殊的 Layout
    3. 继承特定的 View(比如 TextView)
    4. 继承特定的 ViewGroup(比如 LinearLayout)
  2. 自定义 View 须知:
    post
    View#onDetachedFromWindow
    

本章节配套源码 戳我


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java Concurrency in Practice

Java Concurrency in Practice

Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes、Doug Lea / Addison-Wesley Professional / 2006-5-19 / USD 59.99

This book covers: Basic concepts of concurrency and thread safety Techniques for building and composing thread-safe classes Using the concurrency building blocks in java.util.concurrent Pe......一起来看看 《Java Concurrency in Practice》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具