文章目录

  • 一,背景
  • 二,控件优点
  • 三,项目中引入
  • 四,基本使用
    • 4.1 相对位置
    • 4.2 尺寸约束
    • 4.3 宽高比 Ratio
    • 4.4 百分比宽高 Percent
    • 4.5 偏移量 bias
    • 4.6 圆形定位 Circular positioning
    • 4.7 权重 weight
    • 4.8 辅助线 Guideline
    • 4.9 屏障 Barrier
    • 4.10 Group
    • 4.11 隐藏边距 goneMargin
    • 4.12 链 Chains
  • 五,ConstraintLayout 2.0 新特性
    • 5.1 新增VirtualLayouts:Flow布局
    • 5.2 可自定义ConstraintHelper
    • 5.3 新增切换状态布局功能:ConstraintLayoutStates
    • 5.4 新增创建约束工具类:ConstraintProperties
  • PS. 推荐阅读

国际惯例,官网参考文档是最好的学习资料:

使用 ConstraintLayout 构建自适应界面

一,背景

约束布局 ConstraintLayout,也有人把它称作“增强型的相对布局”,扁平式的布局方式,无任何嵌套,减少布局的层级,优化渲染性能。是最受欢迎的 Jetpack 库之一,其实是 Android Studio 2.2 中主要的新增功能之一,也是 Google 在2016年的 I/O 大会上重点宣传的一个功能。AS 已经将它作为新建页面默认布局了。经历这几年的迭代,功能已经非常的成熟,现在 2.0 正式版本也发布了,也许你已熟悉了旧版本中的功能,并开始用它来快速构建复杂的页面布局,而新版本除了包含旧版本中的所有功能之外,还在 AS 中集成了可以直接预览 XML 的工具,甚至可以直接在预览界面中对布局进行编辑。

二,控件优点

ConstraintLayout 可以理解为 RelativeLayout + LinearLayout 的混合强化版,同时新版 Android Studio 的布局编辑器也提供了对 ConstraintLayout 完善的编辑支持。使用 ConstraintLayout 可以很方便地在一个层级上实现复杂的布局,功能也很完善,是 Android 官方目前非常重视的一个 Layout(替代以前的 RelativeLayout),使用 ConstraintLayout 后基本可以抛弃 LinearLayout 和 RelativeLayout 的使用,完全不需要任何嵌套就可以实现复杂的 UI,使用起来特别清爽。减少了很多的嵌套的层级,这样 View 在渲染的时候,减少了很多多余的 measurelayout 的开销,如果嵌套的层次越多,提升的效果越明显。

感兴趣的话看官方给出的性能测试示例:解析ConstraintLayout的性能优势

三,项目中引入

如需在项目中使用ConstraintLayout,请按以下步骤操作:

  1. 确保你的maven.google.com代码库已在模块级build.gradle文件中声明:
repositories {google()
}
  1. 将该库作为依赖项添加到同一个build.gradle文件中,如以下示例所示。请注意,最新版本可能与示例中显示的不同:
dependencies {implementation "androidx.constraintlayout:constraintlayout:2.0.4"// To use constraintlayout in composeimplementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha05"
}
  1. 在工具栏或同步通知中,点击 Sync Project with Gradle Files

现在,你可以使用 ConstraintLayout 构建布局。

四,基本使用

4.1 相对位置

要在ConstraintLayout 中确定 view 的位置,必须至少添加一个水平和垂直的约束。每一个约束表示到另一个 view、父布局或者不可见的参考线的连接或者对齐。如果水平或者垂直方向上没有约束,那么其位置就是0。

下面是 ConstraintLayout 确定位置的属性,这些属性的值即可以是 parent(父布局),也可以是某个 view 的 id,和同类型的RelativeLayout属性很相似:

ConstraintLayout RelativeLayout 作用
layout_constraintLeft_toLeftOf layout_alignLeft 与参照控件左对齐
layout_constraintLeft_toRightOf layout_toRightOf 在参照控件的右边
layout_constraintRight_toLeftOf layout_toLeftOf 在参照控件的左边
layout_constraintRight_toRightOf layout_alignRight 与参照控件右对齐
layout_constraintTop_toTopOf layout_alignTop 与参照控件上对齐
layout_constraintTop_toBottomOf layout_below 在参照控件底部
layout_constraintBottom_toTopOf layout_alignBottom 在参照控件的上部
layout_constraintBottom_toBottomOf layout_above 与参照控件下对齐
layout_constraintBaseline_toBaselineOf layout_alignBaseline 与参照控件基线对齐
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf

说明:这里 start/end 一般情况下和 left/right 是一样的效果,主要是为了做国际化适配,方便从右往左读的语言文字(如阿拉伯文)。

一个简单的页面:

<?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="match_parent"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="左对齐"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="右对齐"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="水平居中"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="垂直居中"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="底部对齐"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="水平居中+垂直居中"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>


居中显示:

<!--
即view的左边对齐父布局的左边,view的右边对齐父布局的右边,除非这个view的大小刚好充满整个父布局;
否则的话,就是水平居中显示了。我们可以理解为有两个相同的力,把view拉到中间。
-->
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

水平方向的相对位置:

<?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="match_parent"><Buttonandroid:id="@+id/btn_center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="水平参照物"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Left_toLeftOf"app:layout_constraintBottom_toTopOf="@id/btn_center"app:layout_constraintLeft_toLeftOf="@id/btn_center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Right_toLeftOf"app:layout_constraintBottom_toTopOf="@id/btn_center"app:layout_constraintRight_toLeftOf="@id/btn_center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Right_toRightOf"app:layout_constraintRight_toRightOf="@id/btn_center"app:layout_constraintTop_toBottomOf="@id/btn_center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Left_toRightOf"app:layout_constraintLeft_toRightOf="@id/btn_center"app:layout_constraintTop_toBottomOf="@id/btn_center"/>
</androidx.constraintlayout.widget.ConstraintLayout>

效果如下:

竖直方向的相对位置:

<?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="match_parent"><Buttonandroid:id="@+id/btn_center"android:layout_width="wrap_content"android:layout_height="100dp"android:text="竖直参照物"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Top_toTopOf"app:layout_constraintTop_toTopOf="@id/btn_center"app:layout_constraintRight_toLeftOf="@id/btn_center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Bottom_toTopOf"app:layout_constraintBottom_toTopOf="@id/btn_center"app:layout_constraintRight_toLeftOf="@id/btn_center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Top_toBottomOf"app:layout_constraintLeft_toRightOf="@id/btn_center"app:layout_constraintTop_toBottomOf="@id/btn_center"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Bottom_toBottomOf"app:layout_constraintLeft_toRightOf="@id/btn_center"app:layout_constraintBottom_toBottomOf="@id/btn_center"/>
</androidx.constraintlayout.widget.ConstraintLayout>

效果如下

4.2 尺寸约束

view 中使用 warp_content 或者固定值等等是没有问题的。但是在 ConstraintLayout 中不推荐使用 match_parent 这个值,如果需要实现跟 match_parent 同样的效果,可以使用 0dp 来代替,其表示 match_parent,即适应约束。其跟 match_parent 还是有区别的,后面的例子(宽高比那一小节)会提到。
我们来看下例子:

<?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="match_parent"><Buttonandroid:id="@+id/btn_center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="wrap_content"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:id="@+id/btn_1"android:layout_width="180dp"android:layout_height="wrap_content"android:text="具体数值:180dp"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toBottomOf="@id/btn_center"/><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:text="0dp(match_parent)"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toBottomOf="@id/btn_1"/></androidx.constraintlayout.widget.ConstraintLayout>

4.3 宽高比 Ratio

ConstraintLayout 中,还可以将宽定义成高的一个比例或者高定义成宽的比率。首先,需要将宽或者高设置为0dp(即match_parent),即要适应约束条件。然后通过 layout_constraintDimensionRatio 属性设置一个比率即可。这个比率可以是一个浮点数,表示宽度和高度之间的比率;也可以是“宽度:高度”形式的比率。比如:

<?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="match_parent"><Buttonandroid:layout_width="wrap_content"android:layout_height="0dp"android:layout_marginTop="30dp"app:layout_constraintTop_toTopOf="parent"android:text="-------------------宽高比2:1-------------------"app:layout_constraintDimensionRatio="2:1"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>


如果宽和高都设置为0dp(match_parent),那么 layout_constraintDimensionRatio 的值需要先加一个"W,"或者"H,"来表示约束宽度或高度。如下:

<?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="match_parent"><Buttonandroid:layout_width="0dp"android:layout_height="0dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintDimensionRatio="H,16:9"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>

4.4 百分比宽高 Percent

ConstraintLayout 还能使用百分比来设置 view 的宽高。要使用百分比,宽或高同样要设置为 0dp(match_parent)。然后设置以下属性即可:

app:layout_constraintWidth_default="percent" //设置宽为百分比,可以设置percent、spread和wrap
app:layout_constraintWidth_percent="0.3" //0到1之间的值,为占父布局宽度的多少
app:layout_constraintHeight_default="percent" //设置高为百分比,可以设置percent、spread和wrap
app:layout_constraintHeight_percent="0.3" //0到1之间的值,为占父布局宽度的多少

例子如下:

<?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="match_parent"><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:text="宽50%"app:layout_constraintWidth_default="percent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintWidth_percent="0.5"/></androidx.constraintlayout.widget.ConstraintLayout>

注:在早期版本中必需手动指定 app:layout_constraintWidth_default=“percent”,在之后的版本中如果设置了app:layout_constraintWidth_percent 属性,则可以不用指定。

效果如下:

官网的介绍是这样的:

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以逗号隔开。

4.5 偏移量 bias

如果想让view的位置偏向某一侧,可以使用以下的两个属性来设置:

layout_constraintHorizontal_bias  //水平偏向
layout_constraintVertical_bias  //竖直偏向

其值同样也是0到1之间。比如,以下例子为横向偏向左侧30%,默认的居中效果就是50%:

<?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="match_parent"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="左边偏向30%"app:layout_constraintHorizontal_bias="0.3"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>

显示效果如下:

4.6 圆形定位 Circular positioning

以一个控件为圆心设置角度和半径定位

  • layout_constraintCircle:关联另一个控件,将另一个控件放置在自己圆的半径上,会和下面两个属性一起使用
  • layout_constraintCircleRadius:圆的半径
  • layout_constraintCircleAngle:圆的角度

4.7 权重 weight

LinearLayout中可以设置权重,ConstraintLayout 同样也有这个属性。通过设置以下两个属性:

app:layout_constraintHorizontal_weight //水平权重
app:layout_constraintVertical_weight //竖直权重

然后将相连的 view 两两约束好即可。如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns: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="match_parent"><Buttonandroid:id="@+id/btn_1"android:layout_width="0dp"android:layout_height="wrap_content"android:text="权重为1"app:layout_constraintHorizontal_weight="1"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toLeftOf="@id/btn_2"/><Buttonandroid:id="@+id/btn_2"android:layout_width="0dp"android:layout_height="wrap_content"android:text="权重为2"app:layout_constraintHorizontal_weight="2"app:layout_constraintLeft_toRightOf="@id/btn_1"app:layout_constraintRight_toLeftOf="@id/btn_3"/><Buttonandroid:id="@+id/btn_3"android:layout_width="0dp"android:layout_height="wrap_content"app:layout_constraintHorizontal_weight="2"android:text="权重为2"app:layout_constraintLeft_toRightOf="@id/btn_2"app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

4.8 辅助线 Guideline

Guideline 可以用来辅助布局,通过 Guideline 能创建出一条水平线或者垂直线,该线不会显示到界面上,但是能够利用这些线条来添加约束去完成界面的布局。

Guideline主要的属性有:

android:orientation="horizontal|vertical"
app:layout_constraintGuide_begin="30dp"
app:layout_constraintGuide_end="30dp"
app:layout_constraintGuide_percent="0.5"<!--
android:orientation=”horizontal|vertical”表示是水平或垂直引导线。
app:layout_constraintGuide_begin=”30dp”,如果是水平引导线,则距离布局顶部30dp,如果是垂直引导线,则距离布局左边30dp。
app:layout_constraintGuide_end=”30dp”,如果是水平引导线,则距离布局底部30dp,如果是垂直引导线,则距离布局右边30dp。
app:layout_constraintGuide_percent=”0.5”,如果是水平引导线,则距离布局顶部为整个布局高度的50%,如果是垂直引导线,则距离布局左边文这个布局宽度的50%。
-->

来看个例子:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns: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="match_parent"><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline_h"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"app:layout_constraintGuide_percent="0.5"/><androidx.constraintlayout.widget.Guidelineandroid:id="@+id/guideline_v"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"app:layout_constraintGuide_percent="0.5"/><Buttonapp:layout_constraintLeft_toLeftOf="@id/guideline_v"app:layout_constraintTop_toTopOf="@id/guideline_h"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="辅助线定位"/>
</androidx.constraintlayout.widget.ConstraintLayout>

如下图所示:

4.9 屏障 Barrier

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

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

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

<?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="match_parent"android:padding="20dp"><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"/><androidx.constraintlayout.widget.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"/></androidx.constraintlayout.widget.ConstraintLayout>

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

4.10 Group

Group用于控制多个控件的可见性。使用非常简单,若 android:visibility="gone" 那么 btn1,btn2 控件都会隐藏。

<androidx.constraintlayout.widget.Groupandroid:layout_width="match_parent"android:layout_height="wrap_content"android:visibility="visible"app:constraint_referenced_ids="btn1,btn2"><Buttonandroid:id="@+id/btn1"android:text="btn1"android:layout_width="wrap_content"android:layout_height="wrap_content"/><Buttonandroid:id="@+id/btn2"android:text="btn2"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.Group>

4.11 隐藏边距 goneMargin

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

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom

4.12 链 Chains

上面这种将相连的 view 两两约束好的实际上就形成了链。在 ConstraintLayout 中可以实现各种不同的链,权重链是其中一种。整个链由链中的第一个view(链头)上设置的属性控制。

官网上一共有4种样式的链:

  • Spread:视图是均匀分布的(在考虑外边距之后)。这是默认值。
  • Spread inside:第一个和最后一个视图固定在链两端的约束边界上,其余视图均匀分布。
  • Weighted:当链设置为 spread 或 spread inside 时,您可以通过将一个或多个视图设置为“match_parent”(0dp) 来填充剩余空间。默认情况下,设置为“match_parent”的每个视图之间的空间均匀分布,但您可以使用 layout_constraintHorizontal_weight 和 layout_constraintVertical_weight 属性为每个视图分配重要性权重。如果您熟悉线性布局中的 layout_weight 的话,就会知道该样式与它的原理是相同的。因此,权重值最高的视图获得的空间最大;相同权重的视图获得同样大小的空间。
  • Packed:视图打包在一起(在考虑外边距之后)。 然后,您可以通过更改链的头视图偏差调整整条链的偏差(左/右或上/下)。
layout_constraintHorizontal_chainStyle // 横向约束链
layout_constraintVertical_chainStyle // 纵向约束链

五,ConstraintLayout 2.0 新特性

官方更新文档:What’s New in 2.1

5.1 新增VirtualLayouts:Flow布局

Flow布局是Chains的强化版,是一种新的VirtualLayouts。用于构建流式排版效果:当出现空间不足时,可自动换行或自动延展到屏幕的另一区域。即当需要对多个View进行流式布局 / 不确定其布局空间的实际尺寸时,就可使用Flow布局。

使用步骤:

  1. 通过属性constraint_referenced_ids获取要引用的视图;
  2. 根据这些视图创建一个虚拟的virtual view group;
  3. 对这些视图进行流式布局。
<androidx.constraintlayout.helper.widget.Flowapp:constraint_referenced_ids="a1,a2,a3"app:flow_wrapMode="aligned"android:layout_width="0dp"android:layout_height="wrap_content"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent" />

核心属性:flow_wrapMode,用于控制元素的排列方式。

属性说明如下:

<androidx.constraintlayout.helper.widget.Flowapp:constraint_referenced_ids="a1,a2,a3"app:flow_wrapMode="aligned"android:layout_width="0dp"android:layout_height="wrap_content"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent" />
<!--
NONE : 默认模式。Views不会被包裹到另一行或列。如果它们在屏幕之外,则不能被看到。
CHAIN : CHAIN与Chains非常相似,可以认为是Chains的强化版本。CHAIN是根据orientation逐行或逐列进行排列的,默认的展示风格是SPREAD。
ALIGNED : ALIGNED模式与CHAIN类似,但链式是在将不同行和列的视图对齐后考虑的,默认的样式是SPREAD。
-->

5.2 可自定义ConstraintHelper

ConstraintHelper 是一个用于记录标记 Views 的 Helper,通过引用指定 Views 从而实现具体效果。

使用场景

  • 辅助布局:创建一个新的布局方式,避免创建新的 ViewGroup 从而加深层级
  • 修改布局:在布局完成后,修改布局效果
  • 重新渲染:在View绘制完成后,对View进行修改、重新渲染效果

具体使用:通过继承 ConstraintHelper 类实现 & 重写所需回调,具体如下所示。

// 继承ConstraintHelper类
class carsonhoTest @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {// 复写常用方法override fun updatePostLayout(container: ConstraintLayout?) {super.updatePostLayout(container)getViews(container).forEach { view ->ViewAnimationUtils.createCircularReveal(view, view.width / 3,view.height / 3, 0f,hypot((view.height / 3.0), (view.width / 3.0)).toFloat()).apply {duration = 2000start()}}}
}// 常用方法说明
init() // 初始化调用
updatePreLayout() // 布局前更新
updatePostLayout() // 布局后更新
updatePostMeasure() // 测量后更新
updatePostConstraints() // 更新约束
onDraw() // 进行绘制

5.3 新增切换状态布局功能:ConstraintLayoutStates

ConstraintLayoutStates 用于根据状态切换不同的布局文件。

具体使用

// 步骤1:创建不同状态的layout xml文件,布局文件的root id相同即可。
// 如:states_1、states_2// 步骤2:在xml文件夹下创建管理文件
<?xml version="1.0" encoding="utf-8"?>
<ConstraintLayoutStates xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"><Stateandroid:id="@+id/state1"app:constraints="@layout/states_1" /><Stateandroid:id="@+id/state2"app:constraints="@layout/states_2" /></ConstraintLayoutStates>
// 步骤3:使用loadLayoutDescription来加载管理文件
val constraintLayout = findViewById<ConstraintLayout>(R.id.constraint_state)
constraintLayout.loadLayoutDescription(R.xml.constraint_layout_states)
constraintLayout.setOnClickListener {// 点击时切换布局文件constraintLayout.setState(R.id.state2, 0, 0)
}

5.4 新增创建约束工具类:ConstraintProperties

ConstraintProperties 是在代码中创建约束的工具类。
具体使用:在该工具类出来前,修改属性的常用方式是:

ConstraintSet().apply {clone(constraintLayout)setTranslationX(R.id.xxx, 32f)setMargin(R.id.xxx, ConstraintSet.START, 42)applyTo(constraintLayout)
}

对于 ConstraintLayoutStates,可使用流式 API 修改属性,更加方便快捷。

ConstraintProperties(findViewById(R.id.xxx)).translationZ(8f).margin(ConstraintSet.START, 8).apply()

PS. 推荐阅读

  • 使用 ConstraintLayout 构建自适应界面【官方文档】
  • 解析ConstraintLayout的性能优势【Google 开发者计划工程师 Takeshi Hagikura】
  • Android新特性介绍,ConstraintLayout完全解析【郭霖,拖拽动图讲解】
  • ConstraintLayout 完全解析,快来优化你的布局吧【张鸿洋】
  • 自律给你自由——设计布局的新姿势【徐宜生】
  • ConstraintLayout使用场景必知必会【徐宜生】
  • 带你了解Android约束布局ConstraintLayout【四月葡萄】
  • ConstraintLayout使用指南
  • 妙用ConstraintLayout的Circular positioning【进阶实战,按钮展开效果】
  • 实战篇ConstraintLayout的崛起之路
  • android ConstraintLayout使用详解
  • ConstraintLayout的使用教程
  • ConstraintLayout 2.0 新特性详解及实战
  • 约束布局ConstraintLayout看这一篇就够了
  • ConstraintLayout看完一篇真的就够了么?
  • 布局优化:9种让你不得不使用约束布局Constraintlayout的场景
  • 万字长文 - 史上最全ConstraintLayout(约束布局)使用详解
  • ConstraintLayout使用大全

约束布局ConstraintLayout相关推荐

  1. 约束布局ConstraintLayout看这一篇就够了

    目录 1.介绍 2.为什么要用ConstraintLayout 3.如何使用ConstraintLayout 3.1 添加依赖 3.2 相对定位 3.3 角度定位 3.4 边距 3.5 居中和偏移 3 ...

  2. Android开发笔记(一百四十九)约束布局ConstraintLayout

    约束布局ConstraintLayout是Android Studio 2.2推出的新布局,并从Android Studio 2.3开始成为默认布局文件的根布局,由此可见Android官方对其寄予厚望 ...

  3. Android :约束布局ConstraintLayout 之 Chains 链式约束

    ConstraintLayout Chains 链式约束 1. 链 简介 ( 1 ) Chains ( 链 ) 简介 2. 创建 链 及 分析 生成的代码 ( 1 ) 创建水平链 ( 2 ) 链创建后 ...

  4. 约束布局ConstraintLayout加快布局速度

    Android Studio2.2更新布局设计器,同时,引人了约束布局ConstraintLayout. 简单来说,可以把它看做是相对布局的升级版本,但是区别与相对布局更加强调约束.何为约束,即控件之 ...

  5. 约束布局ConstraintLayout(官翻篇)

    目录 ConstraintLayout Relative positioning 相对定位 Margins 间距 当关联的控件可见性是GONE的时候 Centering positioning and ...

  6. Android第二讲笔记(约束布局ConstraintLayout)

    目录 为什么要使用约束布局ConstraintLayout? 约束布局基本属性 约束布局简单使用方法 示例 示例一(仿QQ消息) 示例二(仿微信登陆界面) 示例三(仿QQ音乐界面) 补充 写在最后 S ...

  7. 约束布局constraint-layout导入失败的解决方案 - 转

    今天有同事用到了约束布局,但是导入我的工程出现错误  **提示错误:  Could not find com.Android.support.constraint:constraint-layout: ...

  8. 约束布局 ConstraintLayout 的使用

    目录 前言 1.将ConstraintLayout添加到项目中 2.基本规则 3.示例讲解 3.1居中对齐 3.2 排列 3.3引导线Guideline 3.4计算器示例 3.5宽高比示例 3.6Ch ...

  9. Android 约束布局:ConstraintLayout GuidLine

    默认的约束布局.里面控件是居中的 可以使用参考线Guideline做参考 来画出来心仪的位置 这布局在渲染上面是没有什么东西的 就是运行到手机上Guideline 是啥也没有的 究其原因因为 源码的d ...

最新文章

  1. 细胞因子风暴与新冠肺炎
  2. JVM 调优实战--一个案例理解常用工具(命令)
  3. (旧)子数涵数·Flash——遮罩动画
  4. asp.net中获得客户端的IP地址
  5. 浪漫的表白 (5 分)
  6. struts2 resultType为chain时 传值
  7. FreeBSD8下安装软件相关
  8. open_basedir restriction in effect,解决php引入文件权限问题
  9. 一网打尽!2018网络安全事件最全的盘点
  10. ARM中C语言和汇编语言互相调用以及实例
  11. 测试开发工程师的概念怎么来的?
  12. 信息化管理系统(制造业ERP系统)
  13. 4十4十4写成乘法算式_乘法算式怎么写
  14. Linux下软连接的概念
  15. ADT:Queues
  16. 二叉查找树与红黑树原理和程序全面介绍
  17. 国外众测之密码找回漏洞
  18. 数据分析及可视化——京东上销量最高的鞋子
  19. 学口腔医学还是学计算机,我国口腔医学的这“四大家族”,最受学霸欢迎,是真正的金饭碗!...
  20. 数据可视化工具Table-au的破解安装

热门文章

  1. java eventusermodel_异常读取XLSB文件Apache POI java.io.CharConversionException
  2. GaussDB高斯数据库(数据库介绍)
  3. fl水果软件第三方插件FL Studio20.9
  4. Java实现库存管理系统
  5. js作用域及作用域链
  6. IntelliJ IDEA 2020.3.2下载安装教程(公开版)
  7. mysql配置所有人可连接_mysql配置允许外界连接
  8. 接入米家(通过米家购买的WIFI模组 串口方式)
  9. TI CC1310 sub1G的SDK开发之发射功率实测
  10. SAI+Ps日漫漫画培训视频教程