Android :约束布局ConstraintLayout 之 Chains 链式约束
ConstraintLayout Chains 链式约束1. 链 简介( 1 ) Chains ( 链 ) 简介2. 创建 链 及 分析 生成的代码( 1 ) 创建水平链( 2 ) 链创建后的代码及样式( 3 ) 链创建后 生成的 代码3. 链头 及 链的间距( 1 ) 链头设置( 2 ) 链 间距4. 链 的 三种风格( 1 ) 链 风格设置( 2 ) 链 的 三种风格( 3 ) CHAIN_S
ConstraintLayout
Chains 链式约束
1. 链 简介
( 1 ) Chains ( 链 ) 简介
-
1.实现的约束功能 : Chains 约束 提供了一种机制 , 通过 该机制 可以在
单个方向
( 垂直 或 水平 ) 上 控制一组组件的排列分布
; 与此同时 , 另外一个方向上的 约束行为 不受 Chains 影响 , 两个方向的约束是独立的 ; -
2.分组共享空间 : Chains 提供了一个类似于 分组的功能 , 其 包含了多个组件 , 这些组件
共享 水平 或 垂直 方向的空间
; -
3.类似于 LinearLayout 的 weight 功能 : Chains 的功能 与 线性布局 的 weight 属性 设置类似 , 但其功能要比线性布局 强大很多 ;
-
4.Chains 约束方向 : 使用前需要限定一个方向 , 水平方向 , 或者 垂直方向 , 一组组件共享 该方向上的空间 。
2. 创建 链 及 分析 生成的代码
( 1 ) 创建水平链
创建 水平 Chains :
- 1.创建多个 组件 : 先 在 界面中 创建 多个组件 , 其方向 呈 水平放置 , 或 垂直放置 , 此处创建 水平方向的 Chains ( 链 ) ;
- 2.具体创建方法 : 选中 一组 组件 , 然后 右键 选择
Chains -> Create Horizontal Chain
, 即 创建了一个 水平方向的 Chains ( 链式约束 ) ;
( 2 ) 链创建后的代码及样式
Chains 创建后 代码 及 样式 : 下图是 官方配图 , 表示一个 最小的 链 , 只有两个 控件 , 控件两端 约束于 父控件 , 控件之间 互相约束 ;
1.创建完毕后的样式 : Chains 创建完毕后 , 在 Blueprint ( 蓝图 ) 和 Design ( 设计 ) 界面的样式 ; 最左侧 和 最右侧 是 普通的约束 , 中间 和 两侧的元素 是 使用 链 连接起来 的 ;
( 3 ) 链创建后 生成的 代码
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="114dp" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
tools:layout_editor_absoluteY="114dp" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2"
tools:layout_editor_absoluteY="114dp" />
</android.support.constraint.ConstraintLayout>
注意:
bias属性
,表示子控件相对父控件的位置倾向,可以使用属性:
layout_constraintHorizontal_bias
layout_constraintVertical_bias
假设设置控件A相对父控件横向偏差是30%:
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
app:layout_constraintHorizontal_bias详解
布局代码分析如下:
1、Chains 约束 下的 控件 代码 分析 : 两侧 组件 约束与 父控件 , 中间的组件 互相约束 ;
- 1.左侧按钮布局分析 : 其 左侧 约束于 父组件 , 右侧约束于 中间按钮控件 ;
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="114dp" />
- 2.中间按钮布局分析 : 其 左侧 约束于 左边按钮控件 , 右侧 约束于 右侧按钮控件 ;
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
tools:layout_editor_absoluteY="114dp" />
- 3.右侧按钮布局分析 : 其 左侧 约束于 中间按钮控件 , 右侧 约束于 父控件 ;
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2"
tools:layout_editor_absoluteY="114dp" />
3. 链头 及 链的间距
( 1 ) 链头设置
链头 ( Chains Head ) 设置 :
-
1.链的行为控制 : 通过设置 链 的 第一个 控件 的 参数的属性 , 可以控制 Chains 约束 的各种行为 ; 这个 控件 成为 Chains Head ( 链头 ) ;
-
2.链头元素选定 :
- ① 水平方向 : 水平方向上 , 链头 是 最左侧的 控件 ;
- ② 垂直方向 : 垂直方向上 , 链头 是 最顶部的 控件 ;
( 2 ) 链 间距
链 的 间距 :
- 1.设置边距 : 链 中的控件 , 如果设置了 链 的 某个方向上的边距 , 边距效果会体现出来 ,
- 2.空间计算 : 在 CHAIN_SPREAD 样式下 , 如果设置了 Margin , 该距离会从剩余的空间中扣除 ;
4. 链 的 三种风格
( 1 ) 链 风格设置
通过为 链 设置不同的风格 , 可以控制 链的行为 ;
- 1.链风格设置 : 设置 链头 ( 链的 第一个控件 ) 的属性 , 即可为 链 设置不同的风格 ;
- 2.
垂直方向 链
风格设置 : 设置 链头 控件 的layout_constraintVertical_chainStyle
属性 , 即 添加 垂直方向 链 的风格 ; - 3.
水平方向 链
风格设置 : 设置 链头 控件 的layout_constraintHorizontal_chainStyle
属性 , 即 添加 水平方向 链 的风格 ;
( 2 ) 链 的 三种风格
1、CHAIN_SPREAD 风格
: 链中的控件 , 均匀分布在 垂直 或 水平 的 空间中 , 设置链头属性值 " spread
" ; 设置链头如下属性 :
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintVertical_chainStyle="spread"
2.CHAIN_SPREAD_INSIDE
风格 : 与 CHAIN_SPREAD 类似 , 但是 链 两端的控件紧贴被约束的控件位置 , 三个控件还是平均占用指定方向的空间 ; 设置链头如下属性spread_inside
:
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintVertical_chainStyle="spread_inside"
3.CHAIN_PACKED
风格 : 链 上的控件 被打包在一起 , 三个控件 的位置可以 通过控制 app:layout_constraintHorizontal_bias 或 app:layout_constraintVertical_bias 属性值改变 来修改 ; 设置链头如下属性packed
:
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="0.5"
( 3 ) CHAIN_SPREAD 样式 代码示例 及 效果
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<!-- 链头 控件 中设置 Chain 风格 spread -->
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="114dp"
app:layout_constraintHorizontal_chainStyle="spread"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
tools:layout_editor_absoluteY="114dp" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2"
tools:layout_editor_absoluteY="114dp" />
</android.support.constraint.ConstraintLayout>
( 4 ) CHAIN_SPREAD_INSIDE 样式 代码示例 及 效果
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<!-- 链头 控件 中设置 Chain 风格 spread_inside -->
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="114dp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
tools:layout_editor_absoluteY="114dp" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2"
tools:layout_editor_absoluteY="114dp" />
</android.support.constraint.ConstraintLayout>
( 5 ) CHAIN_PACKED 样式 代码示例 及 效果
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<!-- 链头 控件 中设置 Chain 风格 packed-->
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="114dp"
app:layout_constraintHorizontal_chainStyle="packed"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button1"
tools:layout_editor_absoluteY="114dp" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/button2"
tools:layout_editor_absoluteY="114dp" />
</android.support.constraint.ConstraintLayout>
5. 链的权重设置
//设置水平方向的权重
app:layout_constraintHorizontal_weight="1"
//设置垂直方向的权重
app:layout_constraintVertical_weight="1"
( 1 ) 链 的 权重设置
Chain ( 链 ) 的 Weight ( 权重 ) 设置 :
-
1.前提 ( CHAIN_SPREAD 风格 ) : Weight 权重 设置 是在 CHAIN_SPREAD 风格下设置的 ;
-
2.单个 控件 设置 MATCH_CONSTRAINT 尺寸 : 将 链 上控件 的尺寸设置为 MATCH_CONSTRAINT 属性值 , 该控件会将 链上的 水平 或 垂直 方向的剩余空间 全部占满 ;
-
3.多个 控件 设置 MATCH_CONSTRAINT 尺寸 : 如果为 链 上的 多个控件的尺寸设置 MATCH_CONSTRAINT 属性 , 那么这些控件将平均占用链上的剩余空间 ;
-
4.MATCH_CONSTRAINT 尺寸说明 : MATCH_CONSTRAINT 尺寸 等价于 0dip ;
-
5、.多个 控件 设置 Weight 属性 : 要设置权重的控件 , 对应方向的尺寸设置 0dip , 下面的示例 , 中间控件设置权重 2 , 两侧控件设置权重 1 ; 该行为与 LinearLayout 中设置 Weight 属性类似 ;
( 2 ) 链 的 权重设置 代码示例
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn1"
android:layout_width="@dimen/dimen_0dp"
android:layout_height="@dimen/dimen_40dp"
android:text="button1"
app:layout_constraintRight_toLeftOf="@id/btn2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintHorizontal_weight="1"/>
<Button
android:id="@+id/btn2"
android:layout_width="@dimen/dimen_0dp"
android:layout_height="@dimen/dimen_40dp"
android:text="button2"
app:layout_constraintLeft_toRightOf="@id/btn1"
app:layout_constraintRight_toLeftOf="@id/btn3"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="2"/>
<Button
android:id="@+id/btn3"
android:layout_width="@dimen/dimen_0dp"
android:layout_height="@dimen/dimen_40dp"
android:text="button3"
app:layout_constraintLeft_toRightOf="@id/btn2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"/>
</androidx.constraintlayout.widget.ConstraintLayout>
6. 常见问题
不过如果某个控件的宽度设置的不是wrap_content,而是一个具体的宽度dp。还比较大。这个时候布局就会有问题。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorAccent">
<Button
android:id="@+id/sbBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="sb"
app:layout_constraintEnd_toStartOf="@+id/sbBtn01"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sbBtn01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="sb01"
app:layout_constraintEnd_toStartOf="@+id/sbBtn02"
app:layout_constraintStart_toEndOf="@+id/sbBtn"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sbBtn02"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="sb02"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/sbBtn01"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
解决:我们需要把控件的宽度都设置为0dp, 这样能保证控件依然均分,某个控件的内容如果超出宽度也不会影响均分效果。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorAccent">
<Button
android:id="@+id/sbBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="sb"
app:layout_constraintEnd_toStartOf="@+id/sbBtn01"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sbBtn01"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="sb01"
app:layout_constraintEnd_toStartOf="@+id/sbBtn02"
app:layout_constraintStart_toEndOf="@+id/sbBtn"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sbBtn02"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="小星星小星星小星星小星星小星星吃吃吃吃吃吃吃吃吃"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/sbBtn01"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
当然你也可以一些控件自适应wrap_content,剩下的控件0dp,这样就能保证自适应的控件内容显示正常(不换行),但是设置为0dp的控件就会被强制各种压迫:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorAccent">
<Button
android:id="@+id/sbBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="sb"
app:layout_constraintEnd_toStartOf="@+id/sbBtn01"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sbBtn01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="thwrethneyneyjneyjnmtymndrtmndthmetyjkmketuykjmruk"
app:layout_constraintEnd_toStartOf="@+id/sbBtn02"
app:layout_constraintStart_toEndOf="@+id/sbBtn"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/sbBtn02"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="小星星小星星小星星小星星小星星吃吃吃吃吃吃吃吃吃"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/sbBtn01"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
参考
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)