ConstraintLayout学习小结

概览

ConstraintLayout是16年随着Android Studio2.2一起发布的一款布局组件,支持Android2.3及以上的版本,而且从AS2.3开始,新建layout的默认根布局就是ConstraintLayout。ConstraintLayout跟RelativeLayout有点类似,组件的位置根据各兄弟组件及组件与父级之间的相对位置来确定,但是它要比RelativeLayout强大很多,它的出现,应该说是解决了以往开发中过多的布局嵌套带来的卡顿、程序性能不够等问题。与传统的利用XML编辑器编写页面UI不同,AS2.2中的可视化布局编辑器专门针对ConstraintLayout进行了改善,在ConstraintLayout中使用布局编辑器进行控件的拖拽操作和属性调整,比编写XML代码更为简单快速,嗯。。。有点照着UI图绘制高保真原型的味道。

相关概念

上面说到ConstraintLayout主要是在布局编辑器中操作,优化之后,布局编辑器新增了一些功能按钮,这些基本的概念也是依附于布局编辑器解释的。布局编辑器的相关文档:Build a UI with Layout Editor

a.约束(Constraint)

ConstraintLayout,也就是约束布局,顾名思义,像RelativeLayout一样,肯定是在各个View之间有一定的依赖约束关系的,这种关系就称为Constraint。在布局编辑器的蓝图模式(Blueprint)中表现形式是一条细线,如下图中的两条带箭头的细线就是TextView所具有的两个约束(在ConstraintLayout中,每一个View对象至少需要两个约束),蓝图模式会显示选中的View所具有的约束,箭头指向被依赖的View:

constraint

b.锚点

在蓝图模式种选中一个View对象,这个View对象就处于激活状态,可以进行属性设置了,跟以往不同的是,激活状态中的View对象会出现八个锚点,如下图,View对象的每一条边中间有一个空心圆型的约束控制锚点,四个角分别有一个方形的大小控制锚点。约束控制锚点就是用来生成View对象之间的约束的,大小控制锚点不用说也知道可以调节View对象的大小了。

anchors

除此之外,每一个有文字的View(比如TextView或者Button这类的)都会有一个基线锚点,这个是根据文字的基线来对齐View的,如果设置了基线锚点之间的约束,那么这个View的上下两个约束锚点将失效且不能被设置。基线锚点默认是没有启用的,要启用基线锚点,在带文字的View下方点击按钮base-line-anchor就会在View中间出现一条横线:

baseline

c.新增功能按钮

在AS2.3之后,布局编辑器的工具栏中多了这样一排按钮:toolbar,这些按钮就是针对ConstraintLayout设计的。分别代表的功能是:

show-constraints表示是否显示约束,当眼睛打开的时候(鼠标放到上面会显示 Hide Constraints ),这说明只要选中了ContraintLayout这个根布局,其中所有View对象的约束都会显示出来,否则只有在选中某个View的时候才会显示这个View的约束。(图中为关闭状态)
Autoconnect表示是否打开自动设置约束,不过这个设置只针对父布局也就是所在的ConstraintLayout有效。就是说,当这个功能打开时(鼠标放上去显示 Turn off Autoconnect),如果把一个View对象拖入布局的时候,如果靠近父布局边缘会出现参考线(参考线据边缘距离根据最后一个默认间距属性而定),此时放开View会自动添加与父布局的约束,当然只有出现了参考线的那一边会自动约束。如果靠近父布局中其他View对象的话则不会自动约束。(图中为关闭状态,为了看起来不那么费劲,下面附上一张动图看下这个功能的效果,开始处于打开状态,点击这个按钮之后关闭)

auto-connect-gif

clear-all-connects这个就很简单了,如果点击这个按钮,当前ConstraintLayout中View对象的约束都会被清除
infer-constraints这个按钮跟自动设置约束意思差不多,当你把一个View对象拖入ConstraintLayout,随便放一个位置,再点击这个按钮,会根据View当前所在的位置生成与父布局上边和左边的约束,有点绝对坐标的意思
default-margins这个数字就是设置的默认间距了,新增一个约束的时候,两个View之间的间距就根据这个数字而定,点击可以改变它的值

实际操作

1.在项目中加入ConstraintLayout

首先新建一个项目,然后在build.gradle(Module:app)这个文件中添加中央库声明和空间依赖,当然这要确保AS版本在2.2及以上,从AS2.3开始新建的项目默认就包含了ConstraintLayout库的依赖,而且新建的layout.xml文件都是以ConstraintLayout为根布局的。RelativeLayout和LinearLayout也可以用AS自动转变为ConstraintLayout。

1.1.声明中央库maven.google.com

1
2
3
4
5
repositories {
maven {
url 'https://maven.google.com'
}
}

1.2.添加依赖

1
2
3
dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}

做完以上两步之要在 Sync 一下项目就顺利的把ConstraintLayout添加到项目中了。如果需要转换根布局的话,可以在可视化编辑器中 ComponentTree 这个面板右键相应的布局选择 Convert layout to ConstraintLayout 就能将选中的布局自动的转换成ConstraintLayout了。如下图:

convert-to-ConsTraintLayout

可以看到,之前的控件都自动转换到ConstraintLayout中了。如果当中有嵌套布局的话,会去除没有在Java中引用的View Group,将所有控件都放在ConstraintLayout中,由于AS是根据当前屏幕来转换的,所以在自动转换之后还需要微调以保证控件能够适配其他场景或者去掉引用的View Group。

2.添加约束

给View添加约束的操作很简单,选中一个View A,拖住一个约束控制锚点到另一个View B或者父布局边缘,那么View A与View B或者父布局边缘形成一个默认间距的距离,而且是View A往View B或者父布局边缘的方向靠近,如下图:

create-constraint

可以看到如果给Button添加了左边相对于父布局左边的约束,再为右边添加约束的话,之前左边是约束的直线和右边新增的约束都会变成弹簧状,出现这种情况是因为Button的大小固定或者设置为“wrap_content”,说明Button现在是相对于两个约束点居中的状态。

如果要取消这个约束的话,可以点击约束的起点,也就是图中Button的左边约束锚点或右边约束锚点,这样就能取消Button左边或者右边的约束,或者直接使用Button下方的按钮layout-editor-action-clear清除Button所有的约束,当然也能使用工具栏中的清除按钮清除布局中所有View的约束。

添加约束需要注意以下几点:

  • 在ConstraintLayout中,每个View至少要有两个约束,而且要水平和垂直方向各一个,最多当然可以有四个
  • 水平方向的约束锚点只能与水平方向的约束锚点或父布局上下形成约束,垂直方向的约束锚点只能与垂直方向或父布局左右形成约束,基线锚点只能与基线锚点之间形成约束
  • 大概理解为,每一个约束锚点只能作为一个约束的起点,但是可以作为多个约束的终点。也就是说特定的一个约束锚点只能对外形成唯一的一个约束,但是可以有多个其他View的约束锚点连接到它。

当然了,一个约束只能锁定这个锚点所在的方向上的相对位置,例如下图中B被约束到A的右边,C被约束到A的下边,所以B可以上下移动或增加其他约束,C也可以左右移动或增加其他约束。

position-constraint

3.Inspector面板

如果想要改变View的大小或者位置的时候,可以直接在蓝图模式中拖动View对象或者使用大小控制锚点完成,但是通过锚点改变的都是固定大小,并不是很实用,所以新版的布局编辑器中除了新增工具栏的功能按钮,在Properties面板的顶部还增加了一个Inspector面板,这个面板只在ConstraintLayout中有效,它长下面这个样子:

inspector

首先看1处标出的圆点,这个圆点表示在ConstraintLayout中View相应的边设置了约束,如果点击这个圆点,那么这个约束就被清除了,和蓝图模式中View的约束锚点一样。如果没有设置约束,就不会出现圆点,所以图中对应的View的约束表现应该是这样的:

delete_constraint

可以看到,4标出了一个数字,这个数字就是默认的间距,可以直接点击修改相应的间距大小。3标出的是一个弹簧状的图案,这个地方会显示出当前View的宽高模式,就像普通布局中的“wrap_content”、“match_parent”等等,可以通过点击这个区域实现改变,如下图操作:

height_width_mode

这个区域共有三种表现形式:

  • wrap_contentwrap_content:和普通布局中的wrap_content同意,View的大小随内容自适应
  • match_constraintmatch_constraint:这个有点match_parent的味道,但不同的是,只有同一方向上两条边都有约束才会将View的宽或高扩张到match_parent的大小,否则还是会随View中的内容自适应大小。需要注意的是在这种形态下,View的宽或高大小显示为 0dp(注意:没有match_constraint这个属性),而且在ConstraintLayout中应该使用match_constraint来替代match_parent。如果View的宽或高只要有一边处于这种形态,就能看到2处标出的三角形,这个三角形按钮称为Ratio,可设置View的宽高比
  • fixedfixed:这个很明显了,就是设置固定大小的

现在说说2处标出的Ratio的用法,点击Ratio按钮,会在Inspector右下角出现一个设置项

set_ratio

可以在右下角的框中设置比例,这个比例的形式是 width:height ,图中有一个蓝色的“工”字形,那么“工”字的那一竖就表示可以伸缩的,View的大小会以两横为基准,按比例伸缩那一竖的大小,如果两边都是match_constraint的话,可以点击Ratio按钮改变基准,或者说将“工”字形旋转90°,在XML代码中表现形式如下:

1
2
3
<TextView
...
app:layout_constraintDimensionRatio="h,16:9"/>

可以将值中的 h改为 w,h表示高度可伸缩,w表示宽度可伸缩。

最后再看一下5标出了一个带圆圈的值,这个值成为 Constraint Bias(约束偏差),以百分比的形式展示View更靠近哪一边,偏差值默认为50%,如果想改变这个值,拖动这个数值就可以了,如下图操作:

adjust_bias

4.Chains(约束链)

如果多个组件在单一轴向(水平或垂直方向)两两相互之间形成双向约束,那么这几个组件就可以成为Chain。如下图,如果A的右约束锚点与B的左约束锚点之间相互生成约束,那A和B就是一个约束链了。两个轴向的约束链是相互独立的,所以A和B都可以在纵向随意移动。另外,约束链中第一个元素成为链头(Chain Head)。

chains

4.1.创建约束链

创建约束链的方法非常简单,选中所有想要组成链的View,右击选择生成水平或垂直方向的约束链就可以了,如下图:

create_chain

生成约束链的两个元素中间出现了一条链,而且下方都出现了一个新的按钮set_chains_mode,这个按钮可以使约束链在三种模式种转换,这三种模式下面会说到。

嗯。。测试了一下,只有这些View在近似于一条轴上时能成功生成这个轴向的约束链。

4.2.约束链的三种模式

现在我们知道,约束链可以通过按钮set_chains_mode切换三种不同的模式,这三种模式转换到XML代码中就体现在链头的设置上了。在ConstraintLayout中,View对象有两个属性layout_constraintHorizontal_chainStyle和layout_constraintVertical_chainStyle。当我们为链头设置这两个属性中的一个时,就相当于设置这条约束链的模式了,当然这个属性的值有三种可能。

  • spread:设置约束链为Spread模式。该模式下,约束链中的所有元素在相应的轴向被等距分开,如果A、B、C三个元素组成的约束链设置为Spread模式,表现如下图

spread_chain

当该模式下有元素的设置了Match Constraint,那么这几个元素默认会平分剩余的空间,当然也有一个layout_constraintHorizontal_weight或layout_constraintVertical_weight控制其View对剩余空间的占比。例如B、C设置宽度为 0dp,A为 wrap_content,layout_constraintHorizontal_weight属性都默认,则表现如下

weight_chain

  • spread_insdie:设置约束链尾Spread Inside模式。这种模式与Spread模式唯一的不同是两端的元素与ConstraintLayout边缘的距离为0,如下图所示

spread_inside_chain

  • packed:设置约束链为Packed模式。这种模式将所有的元素捆绑到一起,左右两段默认平分剩余的距离,类似于合并并居中的概念。当然左右两段的距离是受链头的Bias控制的。默认情况下Packed模式下的约束链表现如下

packed_chain

如果改变链头也就是A的Bias为<50%,则元素整体靠左偏移,如下图

packed_chain_with_bias

5.GuideLine

为了方便绘制UI,ConstraintLayout还引入了一个辅助的参考线GuideLine。布局中所有的View都可以与GuideLine生成约束,但是在运行时GuideLine是不可见的。GuideLine在工具栏新增按钮的旁边可以找到guideLine,从下拉菜单中可以选择建立纵向或横向的GuideLine,当然也可以右键选择新建相应的Guide,而且可以设置GuideLine的偏移,例如用GuideLine作为辅助时可以这样做

guide_line

实际运行时效果是这样的

guide_line_demo

好了,这些就是ConstraintLayout相关的一些学习笔记了,实际当中还是需要灵活运用来创造更优雅的绘制UI。

呼啦啦...