本篇文章已授权微信公众号 guolin_blog(郭霖)独家发布

一、简介

为啥会取这个标题,绝不是为了噱头,源于最近看了一部国产漫画一武庚纪2,剧情和画质都非常棒的良心之作,且看武庚的崛起 。。。

回忆当初稍微复杂的界面,布局的层级嵌套多层,布局最终会解析成 View 的树形结构,这对渲染性能产生了一定的影响,并且也增大了代码的维护难度。Google 工程师正是考虑到这一因素,推出了 ConstraintLayout

二、ConstraintLayout

ConstraintLayout 翻译为 约束布局,也有人把它称作 增强型的相对布局,由 2016 年 Google I/O 推出。扁平式的布局方式,无任何嵌套,减少布局的层级,优化渲染性能。从支持力度而言,将成为主流布局样式,完全代替其他布局。有个成语用的非常好,集万千宠爱于一身,用到这里非常合适,约束集 LinearLayout(线性布局),RelativeLayout(相对布局),百分比布局等的功能于一身,功能强大,使用灵活。纸上得来终觉浅,绝知此事要躬行。让我们在实际开发的场景中去检验约束布局,在实战中积累经验。

接下来我会以实际开发中遇到的几个场景来讲解。

题外话,本文需要您对 ConstraintLayout 有一定的熟悉了解度,若您对 ConstraintLayout 不熟悉请链接一下地址:

ConstraintLayout 官方文档

郭霖大神的Android新特性介绍,ConstraintLayout完全解析

1、Circular positioning(圆形定位)

标题后面的中文是自己翻译的,可能不是很准确。

官方文档是这么介绍的:

You can constrain a widget center relative to another widget center, at an angle and a distance. This allows you to position a widget on a circle

我是这么理解的,您可以将一个控件的中心以一定的角度和距离约束到另一个控件的中心,相当于在一个圆上放置一个控件。

示例代码如下:

<Button android:id="@+id/buttonA" ... /><Button android:id="@+id/buttonB" ...//引用的控件IDapp:layout_constraintCircle="@+id/buttonA"//圆半径app:layout_constraintCircleRadius="100dp"//偏移圆角度  水平右方向为0逆时针方向旋转app:layout_constraintCircleAngle="45" />

效果图:

图文并茂,理解起来较容易些。圆形定位使用其他布局是很难实现的(除自定义外),该功能在实际的开发中用的并不多,可以用来实现类似钟表的效果。该功能只不过是约束布局的冰山一角,且往下看。

2、WRAP_CONTENT : enforcing constraints(强制约束)

官方文档是这么介绍的:

If a dimension is set to WRAP_CONTENT, in versions before 1.1 they will be treated as a literal dimension -- meaning, constraints will not limit the resulting dimension. While in general this is enough (and faster), in some situations, you might want to use WRAP_CONTENT, yet keep enforcing constraints to limit the resulting dimension. In that case, you can add one of the corresponding attribute

英文一直是我的弱项,我是这么理解的,1.1.0 版本之前是没有这个功能的,说的是控件的宽设置为 WRAP_CONTENT (包裹内容)时,如果实际宽度超过了约束的最大宽度,那么约束会失效(高同理),为了防止约束失效,增加了以下属性:

  • app:layout_constrainedWidth=”true|false” //默认false
  • app:layout_constrainedHeight=”true|false” //默认false

官网并没有过多说明,那么怎么去理解呢,接下来以app:layout_constrainedWidth属性来看两个例子。

a、例子

B 控件位于 A 控件右侧与屏幕右侧的中间。代码如下:

    <Buttonandroid:id="@+id/bt_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="16dp"android:text="A"app:layout_constraintLeft_toLeftOf="parent"/><Buttonandroid:id="@+id/bt_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="B"app:layout_constraintLeft_toRightOf="@+id/bt_1"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toBottomOf="@id/bt_1"/>

那么我改变 B 控件的内容,使宽度增大:

通过效果图可以得出,给 B 控件添加的左右约束失效。为了防止约束失效,在 1.1.0 版本中新增了app:layout_constrainedWidth="true"属性。注意控件的左右都应该有约束条件, 如下:

app:layout_constraintLeft_toRightOf="@+id/bt_1" //控件的左边位于xx控件的右边
app:layout_constraintRight_toRightOf="parent"   //控件的右边位于xx控件的右边

效果图如下:

app:layout_constrainedWidth=”true” 会导致渲染变慢,变慢时长可忽略不计。

b、例子

产品部的美女提出了这样的一个需求,看图:

AB 两控件,BA 的右侧,随着 AB 宽度的增加,B 始终在 A 的右侧,当 AB 控件的宽度之和大于父控件的宽度时,B 要求被完全显示,同时 A 被挤压。我相信大家肯定也遇到过类似的需求,使用线性布局,相对布局会增加层级的嵌套,影响渲染效率,那么ConstraintLayout又是怎么去实现的呢?

代码如下:

    <Buttonandroid:id="@+id/bt_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"app:layout_constrainedWidth="true" // 设置为trueapp:layout_constraintHorizontal_bias="0" // 设置水平偏好为0app:layout_constraintHorizontal_chainStyle="packed" //设置链样式app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@+id/bt_2"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:id="@+id/bt_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="BBBBBBBBBBB"app:layout_constrainedWidth="true"app:layout_constraintLeft_toRightOf="@+id/bt_1"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/>

结合了以下两个属性来达到了需求的效果:

  • app:layout_constraintHorizontal_chainStyle=”packed” //设置链样式
  • app:layout_constraintHorizontal_bias=”0” // 设置水平偏好为0

接下来简单介绍下 chainbias 在后续的百分比布局中会讲到。

Chains(链)

Chains provide group-like behavior in a single axis (horizontally or vertically). The other axis can be constrained independently.

链使我们能够对一组在水平或竖直方向互相关联的控件的属性进行统一管理。成为链的条件:一组控件它们通过一个双向的约束关系链接起来。 并且链的属性是由一条链的头结点控制的,如下:

代码如下:

    <Buttonandroid:id="@+id/bt_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="A" //默认样式app:layout_constraintHorizontal_chainStyle="spread"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@+id/bt_2" /><Buttonandroid:id="@+id/bt_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="B"app:layout_constraintLeft_toRightOf="@+id/bt_1"app:layout_constraintRight_toRightOf="parent" />

那么链有哪些样式,以下图来诠释:

Weighted 样式下,宽或高的维度应设置为match_parent(0dp)

3、MATCH_CONSTRAINT dimensions(填充父窗体约束)

官方文档是这么介绍的:

When a dimension is set to MATCH_CONSTRAINT, the default behavior is to have the resulting size take all the available space. Several additional modifiers are available

在约束布局中宽高的维度 match_parent0dp 代替,默认生成的大小占所有的可用空间。那么有以下几个属性可以使用:

  • layout_constraintWidth_min and layout_constraintHeight_min //设置最小尺寸

  • layout_constraintWidth_max and layout_constraintHeight_max //设置最大尺寸

  • layout_constraintWidth_percent and layout_constraintHeight_percent //设置相对于父类的百分比

开发中有这样一个需求,位于父控件的中间且宽度为父控件的一半,那么我们可以这么去实现:

4、goneMargin(隐藏边距)

当约束目标的可见性为View.GONE时,还可以通过以下属性设置不同的边距值:

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

如以下例子:

Margins and chains (in 1.1), Optimizer (in 1.1) 略。

5、约束之百分比布局

百分比布局大家肯定不会陌生,由于Android的碎片化非常严重,那么屏幕适配将是一件非常令人头疼的事情,百分比适配也就应运而生,约束布局同样也可以实现百分比的功能,并且更加强大,灵活。

经常我们会遇到这样的需求,个人主页要求顶部的背景图宽高 16:9 来适配,如下图:

约束布局的实现方式如下:

    <!-- "W,9:16" 同样的效果 --><ImageView
        android:layout_width="0dp"android:layout_height="0dp"android:scaleType="centerCrop"android:src="@mipmap/icon"app:layout_constraintDimensionRatio="H,16:9"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/>

新增了如下属性:

app:layout_constraintDimensionRatio="H,16:9"

官网的介绍是这样的:

You can also define one dimension of a widget as a ratio of the other one. In order to do that, you need to have at least one constrained dimension be set to 0dp (i.e., MATCH_CONSTRAINT), and set the attribute layout_constraintDimensionRatio to a given ratio

意思是说约束布局支持子控件设置宽高比,前提条件是至少需要将宽高中的一个设置为0dp。为了约束一个特定的边,基于另一个边的尺寸,可以预先附加W,或H以逗号隔开。

然后需求变动,需要将宽度调整为屏幕的一半:

只需要新增 app:layout_constraintWidth_percent="0.5" 属性。

接着需要控件左对齐:

同时新增了app:layout_constraintHorizontal_bias="0"属性。

官网的介绍如下:

The default when encountering such opposite constraints is to center the widget; but you can tweak the positioning to favor one side over another using the bias attributes:

具有相反方向约束的控件,我们可以改变偏好值,来调整位置偏向某一边。有点类似LinearLayoutweight属性。

最后需要调整控件距离顶部的高度为父控件高度的20%:

这里用到了虚拟辅助类 Guideline ,同时1.1.0版本还添加了两个虚拟类BarrierGroup。它们是虚拟对象,并不会占用实际的空间,但可以帮助我们更好更精细地控制布局。综上的需求变化我们可以相对于父控件任意改变控件大小,控件的位置,从而能够更好的适配各大屏幕。

5、Guideline

Guideline 与 LinearLayout 类似可以设置水平或垂直方向,android:orientation="horizontal"android:orientation="vertical",水平方向高度为0,垂直方向宽度为0。Guideline 具有以下的三种定位方式:

  • layout_constraintGuide_begin 距离父容器起始位置的距离(左侧或顶部)
  • layout_constraintGuide_end 距离父容器结束位置的距离(右侧或底部)
  • layout_constraintGuide_percent 距离父容器宽度或高度的百分比

例如,设置一条垂直方向距离父控件左侧为100dp的Guideline:

    <android.support.constraint.Guidelineandroid:layout_width="wrap_content"android:orientation="vertical"app:layout_constraintGuide_begin="100dp"android:layout_height="wrap_content"/>

效果图如下:

6、Barrier

Barrier,直译为障碍、屏障。在约束布局中,可以使用属性constraint_referenced_ids属性来引用多个带约束的组件,从而将它们看作一个整体,Barrier 的介入可以完成很多其他布局不能完成的功能,如下:

开发中有这样的一个需求,看下图:

姓名,联系方式位于 A 区域(随着文本的宽度变化 A 区域的宽度也随之变化),B 区域在 A 区域的右侧。使用传统的布局方式实现嵌套过多,布局不够优雅。那么我们一起来看看约束布局是怎么去实现的:

    <TextViewandroid:id="@+id/tv_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="姓名:"app:layout_constraintBottom_toBottomOf="@+id/et_name"app:layout_constraintTop_toTopOf="@+id/et_name"/><TextViewandroid:id="@+id/tv_contract"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"android:text="联系方式:"app:layout_constraintBottom_toBottomOf="@+id/et_contract"app:layout_constraintTop_toTopOf="@+id/et_contract"/><EditTextandroid:id="@+id/et_name"android:layout_width="0dp"android:layout_height="wrap_content"android:hint="请输入姓名"app:layout_constraintLeft_toLeftOf="@+id/barrier"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><EditTextandroid:id="@+id/et_contract"android:layout_width="0dp"android:layout_height="wrap_content"android:hint="请输入联系方式"app:layout_constraintLeft_toLeftOf="@+id/barrier"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toBottomOf="@+id/et_name"/><android.support.constraint.Barrierandroid:id="@+id/barrier"android:layout_width="wrap_content"android:layout_height="wrap_content"app:barrierDirection="right"app:constraint_referenced_ids="tv_name,tv_contract"/>

barrierDirection 指定方向,constraint_referenced_ids引用的控件 id(多个id以逗号隔开)。

7、Group

Group用于控制多个控件的可见性。

e.g:

android:visibility="gone" 那么 A,B 控件都会隐藏。

三、总结

实战中的情形千变万化,需要大家掌握ConstraintLayout的基本属性,灵活应用。

相信我约束布局会让你爱不释手。

崛起拭目以待。

实战篇ConstraintLayout的崛起之路相关推荐

  1. ConstraintLayout的崛起之路

    一.简介 回忆当初稍微复杂的界面,布局的层级嵌套多层,布局最终会解析成 View 的树形结构,这对渲染性能产生了一定的影响,并且也增大了代码的维护难度.Google 工程师正是考虑到这一因素,推出了 ...

  2. [知识图谱实战篇] 七.HTML+D3实现关系图谱搜索功能

    前面作者讲解了很多知识图谱原理知识,包括知识图谱相关技术.Neo4j绘制关系图谱等,但仍缺少一个系统全面的实例.为了加深自己对知识图谱构建的认识,为后续创建贵州旅游知识图谱打下基础,作者深入学习了张宏 ...

  3. 工作经常使用的SQL整理,实战篇(一)

    工作经常使用的SQL整理,实战篇(一) 原文:工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实战篇,地址一览: 工作经常使用的SQL整理,实战篇(一) 工作经常使用的SQL整理,实 ...

  4. 从零开始学架构5 - 实战篇

    从零开始学架构5 - 实战篇 38 | 架构师应该如何判断技术演进的方向? 潮流派? 保守派? 跟风派? 技术演进的动力 1)对于产品类业务,答案看起来很明显:技术创新推动业务发展! 苹果开发智能手机 ...

  5. sap 标准委外和工序委外_SAP那些事-实战篇-74-公司间委外的几种方式探讨

    我们在<SAP那些事-实战篇-22-关于公司间业务的总结>这一篇中对公司间的转包业务曾经进行过描述,不过这一篇中主要谈到的是SAP中标准的方案,而且是从一方(委托方)的角度来谈,这一篇中我 ...

  6. 反走崛起之路1:创新之西部——西雅图

    反走崛起之路 | 初探美国精神力量的来源(连载) 反走崛起之路0:科技之高地--硅谷 开始觉得硅谷挺好的,直到遇到西雅图,才发现硅谷(不含旧金山)是真没文化,或者说太单调了-- 4月30号,在西雅图, ...

  7. Tiled结合Unity实现瓦片地图——Unity实战篇

    本系列文章由Aimar_Johnny编写,欢迎转载,转载请标明出处,谢谢. http://blog.csdn.net/lzhq1982/article/details/75425915 上文说道,Ti ...

  8. Android开发系列——实战篇5:自适应屏幕尺寸(超详细教程)

    在实战篇4中构建了界面之后,在模拟器中完好的布局,在实际下载到手机上的时候,却出现了布局不协调的问题. 在模拟器Nexus6上的布局界面: 在真机HUWEI P10 Plus上的布局界面: 在真机HU ...

  9. PaddleHub实战篇{ERNIE实现文新闻本分类、ERNIE3.0 实现序列标注}【四】

     相关文章: 基础知识介绍: [一]ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?_汀.的博客-CSDN博客_ernie模型 百度飞桨: ...

最新文章

  1. js删除组数中的某一个元素(完整代码附效果图)
  2. 【廖雪峰python入门笔记】Unicode编码_UnicodeDecodeError处理
  3. VC对话框全屏显示及相应控件位置改变(转)
  4. 首次使用three.js加载obj模型未成功
  5. 由“求最大公约数“引发的思考
  6. 微信小程序实现数组排序(向上向下移动)
  7. 乒乓球单循环赛_重庆市首届乒乓球业余锦标赛开拍 冠军奖3万 总奖金近10万
  8. Vue.js 极简小例: 4 种方式样式绑定、style 的多种方式实现
  9. 台湾计算机读研,台湾省计算机考研_会考教育名副其实
  10. php无限极,php实现无限极分类 - MyClassPHP-Colin主页 - OSCHINA - 中文开源技术交流社区...
  11. UE3 渲染线程的分析及优化
  12. 第一章 微服务网关 - 入门
  13. 使用xml文件存储数据使用xpath查询
  14. java 集合中对象的排序 和去重
  15. 做网站用UTF-8编码还是GB2312编码?
  16. vue-router的简单理解
  17. Project Office 9.0 for mac(任务项目管理软件)
  18. java csv api_CSVAPIforJava
  19. CH579 SPI WS2812B
  20. iPad mini Retina越狱小结【2014年02月06日 - 初稿】

热门文章

  1. 计算机专业全真模拟试卷答案,最新高职考试全真模拟试卷计算机类试题(二、六、七、八、九、十,山东省,有答案)...
  2. 安卓系统文件夹及其文件解析
  3. mt2503 在MMI版本实现AT+CPBF
  4. jdk8+Windows10安装及环境变量配置
  5. 在matlab中怎样把图片转化为数据类型,matlab图像数据类型转换
  6. 昆明拟整治11类陋习 行人翻越隔离设施罚50元
  7. python 运行不过去SyntaxError: Non-ASCII character '\xc2' in file
  8. linux5.8关闭屏幕保护,chia linux
  9. 【钛晨报】字节跳动硬件业务调整,原锤子团队被合并;蔚来回应特斯拉降价冲击:退订是有组织的水军谣言...
  10. 还在纠结配色问题?手把手教你用MATLAB一键生成高质量色卡