美文网首页
View的布局基础

View的布局基础

作者: 名字_都被占了 | 来源:发表于2018-05-12 15:08 被阅读0次

第一部分:Measure测量

从上到下递归地调用每个 View 或者 ViewGroup 的 measure() 方法,测量他们的尺寸并计算它们的位置;measure() 方法被父 View 调用,在 measure() 中做一些准备和优化工作后,调用 onMeasure() 来进行实际的自我测量。

onMeasure() 做的事,View 和 ViewGroup 不一样:
View:View 在 onMeasure() 中会计算出自己的尺寸然后保存;
ViewGroup:ViewGroup 在 onMeasure() 中会调用所有子 View 的 measure() 让它们进行自我测量,并根据子 View 计算出的期望尺寸来计算出它们的实际尺寸和位置然后保存。同时,它也会根据子 View 的尺寸和位置来计算出自己的尺寸然后保存;

介绍一个方法:resolveSize()能让子 View 的计算结果符合父 View 的限制(当然,如果你想用自己的方式来满足父 View 的限制也行)。

重写 onMeasure() 来修改已有的 View 的尺寸的具体做法如下:

第一步:重写 onMeasure() 方法,并在里面调用 super.onMeasure(),触发原有的自我测量;
第二步:在 super.onMeasure() 的下面用 getMeasuredWidth() 和 getMeasuredHeight() 来获取到之前的测量结果,并使用自己的算法,根据测量结果计算出新的结果;
第三步:调用 setMeasuredDimension() 来保存新的结果。

----------------------------------------------

第二部分:Layout布局

从上到下递归地调用每个 View 或者 ViewGroup 的 layout() 方法,把测得的它们的尺寸和位置赋值给它们。layout() 方法被父 View 调用,在 layout() 中它会保存父 View 传进来的自己的位置和尺寸,并且调用 onLayout() 来进行实际的内部布局。

onLayout() 做的事, View 和 ViewGroup 也不一样:
View:由于没有子 View,所以 View 的 onLayout() 什么也不做。
ViewGroup:ViewGroup 在 onLayout() 中会调用自己的所有子 View 的 layout() 方法,把它们的尺寸和位置传给它们,让它们完成自我的内部布局。

----------------------------------------------

第三部分:Draw绘制

1:onDraw()方法,画主体

2:dispatchDraw()方法

继承自ViewGourp的类中有个dispatchDraw()方法(这是绘制子 View 的方法),默认情况下继承自ViewGourp的类是不会执行onDraw()方法的,为了节省系统开销,可以通过设置其背景颜色,或者在构造方法中调用setWillNotDraw(false);来调用它的onDraw()方法。

3:onDrawForeground()方法,画前景

4:draw() 总调度方法

一个 View 的整个绘制过程都发生在 draw() 方法里。背景、主体、子 View 、滑动相关以及前景的绘制,它们其实都是在 draw() 方法里的。onDraw() dispatchDraw() onDrawForeground() 这三个方法在 draw() 中被依次调用,因此它们的遮盖关系是dispatchDraw() 绘制的内容盖住 onDraw() 绘制的内容;onDrawForeground() 绘制的内容盖住 dispatchDraw() 绘制的内容。而在它们的外部,则是由 draw() 这个方法作为总的调度。所以,也可以重写 draw() 方法来做自定义的绘制。

一个完整的绘制过程会依次绘制以下几个内容:
1:背景
2:主体(onDraw())
3:子 View(dispatchDraw())
4:滑动边缘渐变和滑动条
5:前景
一般来说,一个 View(或 ViewGroup)的绘制不会这几项全都包含,但必然逃不出这几项,并且一定会严格遵守这个顺序。

关于绘制方法,有两点需要注意一下:

1:出于效率的考虑,ViewGroup 默认会绕过 draw() 方法,换而直接执行 dispatchDraw(),以此来简化绘制流程。这一点上面已经提到过了,所以如果你自定义了某个 ViewGroup 的子类(比如 LinearLayout)并且需要在它的除 dispatchDraw() 以外的任何一个绘制方法内绘制内容,你可能会需要调用 View.setWillNotDraw(false) 这行代码来切换到完整的绘制流程(是「可能」而不是「必须」的原因是,有些 ViewGroup 是已经调用过 setWillNotDraw(false) 了的,例如 ScrollView)。
2:有的时候,一段绘制代码写在不同的绘制方法中效果是一样的,这时你可以选一个自己喜欢或者习惯的绘制方法来重写。但有一个例外:如果绘制代码既可以写在 onDraw() 里,也可以写在其他绘制方法里,那么优先写在 onDraw() ,因为 Android 有相关的优化,可以在不需要重绘的时候自动跳过 onDraw() 的重复执行,以提升开发效率。享受这种优化的只有 onDraw() 一个方法。

总结


View的绘制流程

View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw()
各步骤的主要工作:
1:测量视图大小。从顶层父View到子View递归调用view.measure方法,measure方法又回调OnMeasure。
2:确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。
3:绘制视图。从顶层父View向子View的递归调用view.draw方法的过程,ViewRoot创建一个Canvas对象,然后调用drawBackground(画背景),OnDraw(画主体),dispatchDraw(画子view,如果有子view),onDrawForeground(画前景及滚动条)。

参考文章
http://hencoder.com/ui-1-5/

相关文章

  • 应用程序UI编程

    基础组件 基础内容组件 表单组件 微信小程序伸缩布局 视图容器 view scroll-viewswiper-view

  • Android 开发艺术探索笔记之四 -- View 的工作原理

    学习内容 View 基础概念 自定义 View View 的底层工作原理测量流程布局流程绘制流程 View 常见回...

  • View的布局基础

    第一部分:Measure测量 从上到下递归地调用每个 View 或者 ViewGroup 的 measure() ...

  • android基础-viewgroup的测量,布局,绘制

    相关文章android基础-view的测量,布局,绘制 知识点 viewgroup的测量 viewgroup的布局...

  • Android 自定义 View

    经过前面几篇文章 View 基础 View 的测量过程 View 的布局和绘制 Android 滑动原理与方式 A...

  • View 的测量

    接着上篇 View 基础 来讲 View 的工作原理,View 的工作原理中最重要的就是测量、布局、绘制三大过程,...

  • Android绘制基础

    Android绘制基础 Layout内部布局的自定义 重写onMeasure()来计算内部布局调用每个子view的...

  • 高级UI------(一)UI的绘制流程

    View是如何被添加到屏幕窗口的 创建顶层布局容器DecorView 在顶层布局容器中加载基础布局ViewGrou...

  • View的绘制流程

    View是如何被添加到品目窗口上 创建顶层布局容器DecorView 在顶层布局中加载基础布局ViewGroup ...

  • UI绘制流程及原理

    1、View是如何被添加到屏幕窗口上 1、创建顶层布局容器DecorView2、在顶层布局中加载基础布局ViewG...

网友评论

      本文标题:View的布局基础

      本文链接:https://www.haomeiwen.com/subject/yxxhdftx.html