一,概述
ConstraintLayout
译为 约束布局,也有人把它称作 增强型的相对布局,由 2016 年 Google I/O 推出。虽然他出来一年多了,但是一直没有时间去研究去使用
。事实上并不是没有时间,而是当时粗略了解了下,感觉这个布局主要是拖控件的,感觉拖控件很low
.所以一直抗拒,心里排斥他。
最近在性能优化里面看到说用ConstraintLayout
替换以前我们使用的RelativeLayout
和LinearLayout
,减少布局层次,所以专门研究了一下。结果不试不知道,一试吓一跳。果然很好用,xml
文件清晰了很多。(而且可以在xml里面自己手动编写属性,和以前使用RelativeLayout等一样,所以内心的抗拒完全消失了。)
扯了这么多,该进入正片时间了。
二、使用
为了使用ConstraintLayout
,我们需要先在app/build.gradle文件中添加依赖,如下所示。
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
}
1、相对定位 (Relative positioning)
作用:设置控件与另外一个控件的位置。
属性如下:
layout_constraintLeft_toLeftOf
layout_constraintLeft_toRightOf
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf
layout_constraintBaseline_toBaselineOf
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
详细说明:
这些属性和RelativeLayout的layout_toRightOf属性的使用方法差不多。
例1
如上图所示:BUTTON1和BUTTON2 2个控件,添加的约束如下
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/button"
app:layout_constraintTop_toTopOf="parent" />
注意:添加约束的时候必须水平和竖直都要添加约束。否则xml会报如下错误```
****The view is not constrained vertically: at runtime it will jump to the left unless you add a vertical constraint.****
2、边距 Margins
作用:设置target控件与source控件的边距。
属性如下:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
注意:边距只能设置精确的值(包括0)和尺寸引用。
当位置约束target
控件View.GONE
时,可用以下margin
属性指示不同的边距值:
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
3、居中设置 Centering positioning
ConstraintLayout
的优势是如何处理不可能的约束。
如上图所示,BUTTON1按钮竖直水平居中。
xml文件如下:
<Button
android:id="@+id/button"
android:layout_width="91dp"
android:layout_height="wrap_content"android:text="Button1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
说明:以上示例,除非
ConstraintLayout
与BUTTON1
的大小完全相同,否则两个约束不会同时满足。这种情况下,约束的作用类似于相反的力牵引控件并均分边距。而控件最终会在父容器中处于居中位置。
4、偏置 Bias
默认约束会促使控件处于居中位置
。此时,可以使用Bias
属性来调整位置,以达到两侧边距不同的效果。
属性如下:
layout_constraintHorizontal_bias
-
layout_constraintVertical_bias
例
如上图所示设置左侧边距为30%代替默认的50%。
代码如下:
<Button
android:id="@+id/button"
android:layout_width="91dp"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
layout_constraintVertical_bias
用法一样。
5、Visibility
当ConstraintLayout
的View设置visibility=View.GONE
时。
如果对其他控件有约束,则仍然会被注重,但是所有边距值都将看似为0。
如上图所示:
BUTTON1
设置visibility=View.GONE
后BUTTON1
隐藏了而且magin
也变成了0
注意:上图使用的边距是由BUTTON2定义的到BUTTON1的距离。有些情况下这可能不是想要设置的边距(例:BUTTON1到父容器一边的边距32dp,BUTTON2到BUTTON1边距68dp,此时设置BUTTON1为GONE,那么BUTTON2到父容器边距变成了68dp)。出于以上原因,当一个作为参考的控件设置为GONE时,可以使用替代的边距值(详看Margins部分)。
6、尺寸约束
ConstraintLayout
可以定义最小宽度和高度。
-
android:minWidth
布局的最小宽度 -
android:minHeight
布局的最小高度
当ContraintLayout
尺寸设置为WRAP_CONTENT
时,将使用最小尺寸。
说明:
ContraintLayout
没有MATCH_PARENT
。只有0dp
,wrap_content
,xxdp
。这三种形式。0dp
的效果和RelativeLayout
里面的MATCH_PARENT
效果一致。
7、比例 Ratio
可以定义一个控件相对于另一个控件的尺寸比例。前提是,需要至少设置一个约束的尺寸为0dp
(可以2个约束都为0dp
),并通过layout_constraintDimentionRatio
属性设置比例。
示例:设置Button的高度与宽度相同
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:text="button1"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintTop_toTopOf="parent" />
说明:必须要加一个约束才能起作用。如果一个约束条件都没有,设置比例没有用。
比例值设置方式:
-
float
浮点值:表示宽高间的比例 -
width:height
方式表示比例
如果宽高都设置为
0dp
,也可以使用比例Ratio。这种情况下,系统会设置最大的那个尺寸来满足所有约束,并保持指定的宽高比。根据一个有尺寸的控件来约束一个指定约束面的控件。可以预先添加W
或H
来分别约束宽高。例:一个尺寸被两个条件约束(如:宽度0dp
并在父容器中居中),那么可以通过在比例Ratio前添加W
或H
,并用,分隔来标识哪一面应该被约束:
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
宽度满屏 高度按照16:9区分
8、链 Chains
链使我们能够对一组在水平或竖直方向互相关联的控件的属性进行统一管理。成为链的条件:一组控件它们通过一个双向的约束关系链接起来
。 并且链的属性是由一条链的头结点
控制的。
例,如下就是个链。
<Button
android:id="@+id/button_a"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#888888"
android:text="A"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintRight_toLeftOf="@+id/button_b"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/button_b"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#FF4081"
android:text="B"
app:layout_constraintLeft_toRightOf="@+id/button_a"
app:layout_constraintRight_toLeftOf="@+id/button_c"
/>
<Button
android:id="@+id/button_c"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#303F9F"
android:text="C"
app:layout_constraintLeft_toRightOf="@+id/button_b"
app:layout_constraintRight_toRightOf="parent"
/>
效果如下
Spread
效果(需要控件宽度或者高度为固定值或者wrap_content)
Spread Inside
效果(需要控件宽度或者高度为固定值或者wrap_content)
<Button
android:id="@+id/button_a"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#888888"
android:text="A"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintRight_toLeftOf="@+id/button_b"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/button_b"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#FF4081"
android:text="B"
app:layout_constraintLeft_toRightOf="@+id/button_a"
app:layout_constraintRight_toLeftOf="@+id/button_c"
/>
<Button
android:id="@+id/button_c"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#303F9F"
android:text="C"
app:layout_constraintLeft_toRightOf="@+id/button_b"
app:layout_constraintRight_toRightOf="parent"
/>
Weighted Chain
效果(需要控件宽度或者高度设置为0dp)
android:id="@+id/button_a"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="#888888"
android:text="A"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintRight_toLeftOf="@+id/button_b"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_weight="2"
/>
<Button
android:id="@+id/button_b"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="#FF4081"
android:text="B"
app:layout_constraintLeft_toRightOf="@+id/button_a"
app:layout_constraintRight_toLeftOf="@+id/button_c"
app:layout_constraintHorizontal_weight="2"
/>
<Button
android:id="@+id/button_c"
android:layout_width="0dp"
android:layout_height="40dp"
android:background="#303F9F"
android:text="C"
app:layout_constraintLeft_toRightOf="@+id/button_b"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="1"
/>
Packed Chain
效果(需要控件宽度或者高度为固定值或者wrap_content)
<Button
android:id="@+id/button_a"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#888888"
android:text="A"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintRight_toLeftOf="@+id/button_b"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_weight="2"
/>
<Button
android:id="@+id/button_b"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#FF4081"
android:text="B"
app:layout_constraintLeft_toRightOf="@+id/button_a"
app:layout_constraintRight_toLeftOf="@+id/button_c"
app:layout_constraintHorizontal_weight="2"
/>
<Button
android:id="@+id/button_c"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#303F9F"
android:text="C"
app:layout_constraintLeft_toRightOf="@+id/button_b"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_weight="1"
/>
Packed Chain with Bias
效果(需要控件宽度或者高度为固定值或者wrap_content)
android:id="@+id/button_a"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#888888"
android:text="A"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintRight_toLeftOf="@+id/button_b"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_bias="0.7"
/>
<Button
android:id="@+id/button_b"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#FF4081"
android:text="B"
app:layout_constraintLeft_toRightOf="@+id/button_a"
app:layout_constraintRight_toLeftOf="@+id/button_c"
/>
<Button
android:id="@+id/button_c"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="#303F9F"
android:text="C"
app:layout_constraintLeft_toRightOf="@+id/button_b"
app:layout_constraintRight_toRightOf="parent"
/>
9、Guideline
Guideline
与 LinearLayout
类似可以设置水平或垂直方向。
android:orientation="horizontal"
android:orientation="vertical"
水平方向高度
为0
,垂直方向宽度
为0
。
Guideline
具有以下的三种定位方式:
layout_constraintGuide_begin
距离父容器起始位置的距离(左侧或顶部)
layout_constraintGuide_end
距离父容器结束位置的距离(右侧或底部)
layout_constraintGuide_percent
距离父容器宽度或高度的百分比
例如,设置一条垂直方向距离父控件40%的Guideline
:
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.4" />
10、MATCH_CONSTRAINT dimensions
在约束布局中宽高的维度 match_parent
被 0dp
代替,默认生成的大小占所有的可用空间。那么有以下几个属性可以使用:
layout_constraintWidth_min
和layout_constraintHeight_min
//设置最小尺寸
layout_constraintWidth_max
和layout_constraintHeight_max
//设置最大尺寸
layout_constraintWidth_percent
和layout_constraintHeight_percent
//设置相对于父类的百分比
11、Barrier
Barrier
,障碍、屏障。Barrier
是一个看不见的视图,其中包含您用来形成“Barrier
”的观点。如果其中一个视图增长,则Barrier将其大小调整为所引用项目的最大高度或宽度。Barrier可以是垂直或水平的,并且可以创建到引用视图的顶部、底部、左侧或右侧。在约束布局中,可以使用属性constraint_referenced_ids
属性来引用多个带约束的组件,从而将它们看作一个整体,Barrier 的介入可以完成很多其他布局不能完成的功能。
例如
姓名,联系方式位于左边区域,输入框在右边区域,输入框随着左边区域的变化而移动。使用传统的布局方式实现嵌套过多,布局不够优雅。那么我们一起来看看约束布局是怎么去实现的:
<TextView
android: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"
app:layout_constraintLeft_toLeftOf="parent"
tools:layout_editor_absoluteX="0dp" />
<TextView
android: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"
app:layout_constraintLeft_toLeftOf="parent"
tools:layout_editor_absoluteX="0dp" />
<EditText
android: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"/>
<EditText
android: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.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="tv_name,tv_contract"/>
12、Group
Group
用于控制多个控件的可见性。
用app:constraint_referenced_ids
绑定控件。
例如把上一个例子的联系方式和对应的输入框隐藏,只需要这样做
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="tv_contract,et_contract"/>
13、WRAP_CONTENT : enforcing constraints(强制约束)
控件的宽设置为 WRAP_CONTENT
(包裹内容)时,如果实际宽度超过了约束的最大宽度,那么约束会失效(高同理),为了防止约束失效,增加了以下属性:
app:layout_constrainedWidth
=”true
|false
” //默认false
app:layout_constrainedHeight
=”true
|false
” //默认false
写在最后
注意事项
-
android.support.constraint.ConstraintLayout 1.1.x
以上才有百分比属性,否则报错 - 要使用
app:layout_constraintVertical_bias="0.1"
设置的属性生效,前置条件是设置了top和bottom的约束,app:layout_constraintHorizontal_bias
,要设置左右的约束,左右的约束只要设置一个就可以使用了。 - 使用百分比尺寸的时候,应当设置宽高为
0dp
。 -
constraintLayout
支持子控件设置其宽高比,要使该特性生效至少需要将宽高中的一个设置为0dp
-
ConstraintLayout
如果不是根布局,布局里的子控件的约束不能设置为"parent"
,要设置@+id/父控件id