ContraintLayout 属性
本文基于ContraintLayout 1.1版本, 参考ContraintLayout官方文档并结合实际的例子说明
ContraintLayout 有以下作用:
- Relative positioning 相对位置
- Margin 边距
- Centering position 中间位置
- Visibility behavior 可见性行为
- Dimension constraints 尺寸约束
- Chains 链
- Virtual Helpers objects 虚拟帮助工具类
- Optimizer 优化
相对位置
类似于RelativeLayout布局,例如:相对父类的最左边,相对某个View的左边 等等
这种属性有很多,就举例两个属性:
layout_constraintLeft_toLeftOf
自身的左边相对于谁的左边, 如果相对于父View,就用parentlayout_constraintLeft_toRightOf
自身的左边相对于谁的右边, 如果相对于父View,就用parent
边距
边距属性继承ViewGroup.LayoutParam, 如下所示:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
但是需要注意的是:
-
设置的边距必须>= 0 。
-
设置的边距要和正确的相对位置约束一起使用才有效过,例如:
app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="10dp" //layout_marginTop要和layout_constraintTop_x 一起使用才有效,单独layout_marginTop是无效的
View的可见或不可见时呈现不同边距
用于设置某个View隐藏时的边距。需求有时A-View的可见或不可见时,B-View的边距会呈现不同的边距 。这是可以用到如下属性:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
但是需要注意的是:
-
设置的边距要和正确的相对位置约束一起使用, 并且这个约束是作用在目标View时才有效过,例如:
<TextView android:id="@+id/tv_a" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" android:visibility="gone" /> <TextView android:id="@+id/tv_b" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintRight_toLeftOf="@+id/tv_a" app:layout_goneMarginRight="20dp" /> // layout_goneMarginRight 这是属性是设置右边距, // 要与layout_constraintRight_toLeftOf结合使用采用效果。 // layout_constraintRight_toLeftOf属性是自身view的右边相对 // 于tv_a的左边,也就是自身的view在tv_a的左边,只有在tv_a的左边时, // tv_a隐藏了layout_goneMarginRight才有效果。
中间位置与偏移量
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
看上面的代码,一个Button在父类左边, 同时又在父类右边,如果这个Button的宽度不是和父View相同就不可能同时满足两个条件。但是父类是ConstraintLayout布局,这个Button的宽度小于父View的宽度时,同时设置app:layout_constraintLeft_toLeftOf="parent", app:layout_constraintRight_toRightOf="parent"时会使该Button位于父类的中心。layout_constraintLeft_toLeftOf, layout_constraintRight_toRightOf 这两个属性也可以作用于其他View,达到位于该View中心位置。
Bias 偏移量
当A同时设置了layout_constraintLeft_toLeftOf和layout_constraintRight_toRightOf在一个B-View时, 你还可以通过layout_constraintHorizontal_bias属性移动A在B-View某个位置上。layout_constraintHorizontal_bias的值是0-1之间,0.5 就是在B-View的中间。
同理layout_constraintVertical_bias 是作用在垂直方向上的,结合layout_constraintBottom_toBottomOf和layout_constraintTop_toTopOf使用。
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3333"
android:gravity="center"
android:textSize="18sp"
android:text="HHHHHHH"
/>
</android.support.constraint.ConstraintLayout>
稍微解析一下bias这个属性,以layout_constraintHorizontal_bias为例,看上面的代码和效果图,水平bias属性设置了0.3333, 大约是1/3。 上图中C为手机的左边缘,D为手机右边缘,A和B分别是TextView的左右边缘。
0.3333 = CA / BD。很多人会误以为CA / CD, 这个要注意。总结起来就是bias属性的值等于该View左边到父view左边距离 除以该View右边到父view右边距离
Circular positioning 圆形位置
你可以约束一个View的中心相对于另一个View的中心。
layout_constraintCircle
: references another widget id 另一个View的idlayout_constraintCircleRadius
: the distance to the other widget center。半径layout_constraintCircleAngle
: which angle the widget should be at (in degrees, from 0 to 360) 角度
可能有些人觉得没卵用,下面举个栗子:
先来效果张图,有张小圆图的圆心需要放在一张大图的下面中心位置,(用相对布局之类不好搞了吧.....)
<ImageView
android:id="@+id/iv_shop_big_photo"
android:layout_height="200dp"
tools:srcCompat="@drawable/ic_big_shop"
android:layout_width="match_parent"
android:scaleType="fitXY"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<ImageView
android:id="@+id/iv_shop_logo"
android:layout_width="56dp"
android:layout_height="56dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:srcCompat="@drawable/ic_home_category"
app:layout_constraintCircle="@+id/iv_shop_big_photo"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="180"
/>
上面代码就能达到效果啦,半径为大图高的一半,角度是180度。
Visibility behavior 可见性行为
就布局计算而言,GONE的View仍然是其中的一部分,具有重要的区别:
-
对于布局的传递,它们的尺寸将被视为零(基本上,它们将被解析为一个点)
-
如果他们对其他小部件有约束,约束仍然有效,但任何边距都会等于零
Dimensions constraints 尺寸约束
最低限度尺寸
-
android:minWidth
set the minimum width for the layout -
android:minHeight
set the minimum height for the layout -
android:maxWidth
set the maximum width for the layout -
android:maxHeight
set the maximum height for the layoutConstraintLayout的子View设置wrap_content时才有效
尺寸约束
android:layout_width
andandroid:layout_height
有三种值:
-
准确的值,例如10dp
-
wrap_content
-
用
0dp
相当于match_contraint, 可以结合约束来限制宽高尺寸。官方推荐:少用match_parent, 多用0dp
当使用0dp,没加任何约束属性,就等于match_parent
强制约束
当设置了wrap_content, 约束不会限制view的尺寸。当时你可以用app:layout_constrainedWidth="true|false"或者app:layout_constrainedHeight=”true|false”来约束尺寸, 设置true就是约束。
下面举个栗子:
<ConstraintLayout>
<View
android:id="@+id/view"
android:layout_width="320dp"
android:layout_height="24dp"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:id="@+id/tv_c"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
app:layout_constrainedWidth=”true|false” // 默认是false
app:layout_constraintLeft_toRightOf="@+id/view"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCDEFGHI"
/>
</ConstraintLayout>
图一
图二
图一没有app:layout_constrainedWidth属性,该属性默认是false; 图二app:layout_constrainedWidth的属性为true。TextView 虽然设置了layout_constraintLeft_toRightOf在红色View的右边约束,但并没有限制宽度,需要用layout_constrainedWidth属性来限制宽度。
0dp使用
针对约束来限制大小,还有一些属性:
layout_constraintWidth_min
andlayout_constraintHeight_min
: will set the minimum size for this dimension 设置最小尺寸layout_constraintWidth_max
andlayout_constraintHeight_max
: will set the maximum size for this dimension 设置最大尺寸layout_constraintWidth_percent
andlayout_constraintHeight_percent
: will set the size of this dimension as a percentage of the parent 设置百分比
上面这些属性需要设置了0dp才能生效。下面举些个栗子:
- 栗子1,设置了layout_width="0dp", app:layout_constraintWidth_min="50dp", 限制了最小宽度为50dp
<android.support.constraint.ConstraintLayout>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="B"
android:id="@+id/tv_b"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/tv_b"
app:layout_constraintWidth_min="50dp"
android:gravity="center"
android:textSize="18sp"
android:lines="1"
android:text="A"
/>
</android.support.constraint.ConstraintLayout>
- 栗子2, app:layout_constraintWidth_percent="0.5" 设置了宽度为父View宽的一半
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
![](https://user-gold-cdn.xitu.io/2019/1/4/168176735e1d9c4f?w=624&h=200&f=png&s=36404)
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="B"
android:id="@+id/tv_b"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/tv_b"
app:layout_constraintWidth_percent="0.5"
android:gravity="center"
android:textSize="18sp"
android:lines="1"
android:text="A"
/>
比例
你可以定义宽和高之间比例。设置宽高比例至少一边尺寸设置为0dp, 要有个基准(基于宽还是高), 属性如下:
- layout_constraintDimensionRatio 它的值可以是float,也可以是width:height, 当没有基准时,可以(W/H,width:height)
<android.support.constraint.ConstraintLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="1:2"
android:gravity="center"
android:textSize="18sp"
android:text="ABCD"
/>
</android.support.constraint.ConstraintLayout>
上面效果layout_constraintDimensionRatio设置了1:2, 就是宽 : 高 = 1 :2 , 宽为wrap_content,高为0dp,所有宽根据text是一个准确的宽,然后高 = 宽 x 2 , 所有就呈现了上面的效果。
下面再看个效果,
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="1:2"
android:gravity="center"
android:textSize="18sp"
android:text="ABCD"
/>
看效果图可能会觉得有点怪,设上面例子的区别是 宽为0dp,高为wrap_content, 宽高比还是1 :2。为什么会出现这个情况,是因为基准不同,高为wrap_content,所以这次高是基准, 至于为什么是这个效果,自己去看源码,不深入啦。
Chains 链
Creating a chain 创建链
不是什么情况都是链,如果一组View通过双向连接链接在一起,则它们被视为链。下图就是一个链:
Chain heads 链头
链的属性是由在链的第一个元素上设置控制, 第一个元素被称为链头。
如上图所示,A就是链头。
链头: 水平方向是最左边的一个,垂直方向是最上面一个
Chain Style 链样式
定义链样式使用layout_constraintHorizontal_chainStyle 或者 layout_constraintVertical_chainStyle,分别对应水平和垂直方向, 这个属性只作用在第一个元素(链头)才有效, 它的值有如下几个:
CHAIN_SPREAD
-- 元素将会被扩展 (默认的属性)- Weighted chain -- 在
CHAIN_SPREAD
模式下, 如果一些View被设置MATCH_CONSTRAINT了,可以利用权重等分空间 CHAIN_SPREAD_INSIDE
-- 和CHAIN_SPREAD相似, 但链条的终点不会分散开来CHAIN_PACKED
-- 这些元素会被包在一起,默认是放在中间, 可以结合水平或者垂直bias属性分配位置。
官方介绍图:
下面一一代码举例:- Spread Chain 的效果
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_chainStyle="spread" //Spread Chain 作用与链头
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
- Spread Inside Chain 的效果
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_chainStyle="spread_inside" //Spread Inside Chain 作用与链头
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
- Pick Chain 与 Pick Chain with Bias 的效果
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_chainStyle="packed" // Packed Chain
app:layout_constraintHorizontal_bias="0.2" // Bias 属性
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
A距离左边占0.2比例,layout_constraintHorizontal_bias = 0.2; 当不加layout_constraintHorizontal_bias属性时,默认是0.5, 效果如下图:
Weighted chains 权重链
使用权重属性, 需要View被设置MATCH_CONSTRAINT(也就是0dp)
- layout_constraintHorizontal_weight
- layout_constraintVertical_weight
下面是代码示例, 使用weight把3个View分成1:2:2 的比例:
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_01"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_02"
app:layout_constraintHorizontal_weight="1.0"
android:text="ABCD-01"
/>
<TextView
android:id="@+id/tv_02"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_01"
app:layout_constraintRight_toLeftOf="@+id/tv_03"
app:layout_constraintHorizontal_weight="2.0"
android:text="ABCD-02"
/>
<TextView
android:id="@+id/tv_03"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/tv_02"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="2.0"
android:text="ABCD-03"
/>
</android.support.constraint.ConstraintLayout>
Virtual Helper objects 虚拟助手类
Guideline
本身继承View,0 宽度, 0高度。
-
app:layout_constraintGuide_begin 与父类左边的距离
-
app:layout_constraintGuide_end 与父类右边的距离
-
app:layout_constraintGuide_percent 占父类总宽度的百分比
-
android:orientation 指引线的方向
-
<android.support.constraint.ConstraintLayout> <android.support.constraint.Guideline android:id="@+id/guide_line_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintGuide_percent="0.1" android:orientation="vertical" /> <android.support.constraint.Guideline android:id="@+id/guide_line_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintGuide_begin="100dp" android:orientation="horizontal" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toRightOf="@+id/guide_line_vertical" app:layout_constraintTop_toTopOf="@+id/guide_line_horizontal" android:text="Guide Line" /> </android.support.constraint.ConstraintLayout>
Barrier
Barrier本身继承View,0 宽度, 0高度。作用:引用多了View创建一个屏障。
- barrierDirection 方向
- constraint_referenced_ids View ids 用逗号隔开
下面用一个场景来说明:
如上图所示,3个TextView, C在 A和B右边,但是A,B长度不定。通常我们可以用一个ViewGroup包含A和B,C在那个ViewGroup的右边就可以啦。但是这样就多了一层布局,ConstraintLayout目的是减少层级,这时Barrier就可以发挥作用力,Barrier可以在A和B最右边创建一个竖立屏障,C约束在这个屏障即可。
代码如下:
<android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_b_01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/s_01"
app:layout_constraintTop_toBottomOf="@+id/tv_b_02"
app:layout_constraintLeft_toLeftOf="parent"
/>
<TextView
android:id="@+id/tv_b_02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
android:text="@string/s_02" />
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="tv_b_01,tv_b_02"
/>
<TextView
android:id="@+id/tv_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:text="@string/s_content"
app:layout_constraintLeft_toRightOf="@+id/barrier" />
</android.support.constraint.ConstraintLayout>
Group
Group本身继承View,0 宽度, 0高度。
用来控制一群View的可见性,代码实例:
<TextView
android:id="@+id/tv_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ABCDEFG"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<TextView
android:id="@+id/tv_111"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HIJKLMN"
app:layout_constraintTop_toBottomOf="@+id/tv_center"
app:layout_constraintLeft_toLeftOf="@+id/tv_center"
/>
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_center, tv_111"
/>
如上面代码所示,Group使用constraint_referenced_ids属性把两个view的id弄成了一个群体,把这两个view隐藏啦。Group也可以代码去控制。
Optimizer 优化
使用属性app:layout_optimizationLevel="direct|barrier|chain"制定优化
- none : 没有任何优化
- standard : 默认 (direct and barrier)
- direct : 优化直接约束
- barrier : 优化barrier屏障约束
- chain : 优化链约束 (实验功能)
- dimensions : 优化View的测量 (实验功能), 减少测量次数