ConstraintLayout 是 Android Studio 2.2 中主要的新增功能之一,也是Google在去年的I/O大会上重点宣传的一个功能。ConstraintLayout 非常适合使用可视化的方式来编写界面,但并不太适合使用 XML 的方式来进行编写。另外,ConstraintLayout还有一个优点,它可以有效地解决布局嵌套过多的问题,它有点类似于 RelativeLayout,但远 比RelativeLayout 要更强大。
1、常用相对位置约束
<!-- 各个边的相对关系 -->
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
<!-- RTL Layout兼容(可以不考虑) -->
layout_constraintStart_toEndOf
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf
简单示例:
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintBaseline_toBaselineOf="@+id/TextView1"
android:background="@color/colorPrimary"
android:text="TextView2"/>
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/TextView1"
android:background="@color/colorPrimaryDark"
android:text="TextView3"/>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
注意:约束布局中必须要约束控件位置,即左和右,上和下要至少有一侧进行约束。
2、控件居中(同时约束左和右,上和下)
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
3、角度定位
<!-- 相对控件 -->
app:layout_constraintCircle="@+id/textView"
<!-- 角度 -->
app:layout_constraintCircleAngle="120"
<!-- 距离 -->
app:layout_constraintCircleRadius="150dp"
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:gravity="center"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintCircle="@+id/TextView1"
app:layout_constraintCircleAngle="120"
app:layout_constraintCircleRadius="150dp"
android:background="@color/colorPrimary"
android:text="TextView2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
4、边距
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
很熟悉,这里不介绍了
goneMargin:用于约束的控件可见性被设置为gone时候使用的margin值
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_goneMarginLeft="10dp"
android:background="@color/colorPrimary"
android:text="TextView2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:正常情况和隐藏TextView1
5、偏移
实现控件居中偏移其实利用边距就能实现,但ConstraintLayout还提供了比例偏移的属性:
<!-- 水平偏移 -->
layout_constraintHorizontal_bias
<!-- 垂直偏移 -->
layout_constraintVertical_bias
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.3"
android:background="@color/colorAccent"
android:text="TextView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
6、尺寸约束
(1)指定尺寸xxdp
(2)wrap_content:控件自己计算大小,此时可以使用下面属性控制最大最小宽高
<!-- 最小的宽度 -->
android:minWidth
<!-- 最小的高度 -->
android:minHeight
<!-- 最大的宽度 -->
android:maxWidth
<!-- 最大的高度 -->
android:maxHeight
(3)使用 0dp (MATCH_CONSTRAINT)
官方不推荐在ConstraintLayout中使用match_parent,可以设置 0dp 配合约束代替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">
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
(4)宽高比
当宽或高至少有一个尺寸被设置为0dp时,可以通过属性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">
<TextView
android:id="@+id/TextView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintDimensionRatio="1:1"
android:background="@color/colorAccent"
android:text="TextView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
7、约束链
第一个控件为链头可以使用layout_constraintHorizontal_chainStyle设置约束链模式:
CHAIN_SPREAD —— 展开元素 (默认);
CHAIN_SPREAD_INSIDE —— 展开元素,但链的两端贴近parent;
CHAIN_PACKED —— 链的元素将被打包在一起。
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/TextView2"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@+id/TextView1"
app:layout_constraintRight_toLeftOf="@+id/TextView3"
android:background="@color/colorPrimary"
android:text="TextView2"/>
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/TextView2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorPrimaryDark"
android:text="TextView3"/>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果(三种模式):
同时,还可以使用layout_constraintHorizontal_weight设置权重
8、屏障Barrier
例如左侧多个控件长度不固定,右侧控件需要在较长控件的右侧
<!-- 位置:bottom、left、right、top -->
app:barrierDirection
<!-- 引用的控件,多个用“,”隔开 -->
app:constraint_referenced_ids
<?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">
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
<TextView
android:id="@+id/TextView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/TextView1"
app:layout_constraintLeft_toLeftOf="parent"
android:background="@color/colorPrimary"
android:text="TextTextView2"/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="TextView1,TextView2" />
<TextView
android:id="@+id/TextView3"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintLeft_toRightOf="@+id/barrier"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/TextView2"
android:background="@color/colorPrimaryDark"
android:text="TextView3"/>
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果:
9、Group
Group可以把多个控件归为一组,方便隐藏或显示一组控件。例如有TextView1、TextView2、TextView3,用Group将TextView1、TextView3归为一组隐藏。
<androidx.constraintlayout.widget.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="TextView1,TextView3" />
10、Placeholder
Placeholder是占位符。在Placeholder中可使用setContent()设置另一个控件的id,使这个控件移动到占位符的位置。
<?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">
<androidx.constraintlayout.widget.Placeholder
android:id="@+id/placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:content="@+id/TextView1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
android:text="TextView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
上面代码中TextView1本来是应该在布局的右侧顶部,然后使用占位符后,控件最后显示在左侧顶部。
11、Guideline
Guildline像辅助线一样,在预览的时候帮助你完成布局
<!-- 辅助线方向 垂直vertical,水平horizontal -->
android:orientation
<!-- 开始位置 -->
layout_constraintGuide_begin
<!-- 结束位置 -->
layout_constraintGuide_end
<!-- 距离顶部的百分比(orientation = horizontal时则为距离左边) -->
layout_constraintGuide_percent
<?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">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="200dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="@+id/TextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline1"
android:background="@color/colorAccent"
android:text="TextView1" />
</androidx.constraintlayout.widget.ConstraintLayout>
运行效果: