前言
什么是约束布局(ConstraintLayout)
我们可以理解为增强版/升级版的相对布局(RelativeLayout)。
Android Studio 从版本2.3开始创建xml默认的根布局就是约束布局,相信大家对相对布局已经是使用的非常6了,所有在使用约束布局的话就会比较轻松。
那么既然已经有相对布局了,为什么还要用约束布局呢?最核心就是:
让布局扁平化,减少布局嵌套的层次,提高渲染效率,提升应用性能。
所以说约束布局还是很有必要学一学的,最起码在性能优化方面是很有帮助的。
下面就一起开始学习吧!
废话不多说,直接进入主题。
举个最简单的栗子:
将一个在ConstraintLayout中居中,如下:
代码很简单,就是给TextView添加上下左右边界的约束即可。所以写约束布局就是写控件的边界约束。
下面我们先介绍下约束属性的写法以及含义。
app:layout_constraintStart_toStartOf="parent"
我们来解释下属性:
第一个start代表的是控件自身的约束方向。
第二个start代表的目标控件的约束方向。
第三个parent代表的是和那个控件建立约束。如果是父控件,就填parent,如果是其他控件,就填写控件的id。
下面我们就以最实用的现实场景来简单学习下ConstraintLayout。
- 控件水平排列
代码如下:<?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" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:id="@+id/common_textview" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="50dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/common_textview2" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintStart_toEndOf="@+id/common_textview" app:layout_constraintTop_toTopOf="@+id/common_textview" /> <TextView android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintStart_toEndOf="@+id/common_textview2" app:layout_constraintTop_toTopOf="@+id/common_textview" /> </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:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:id="@+id/common_textview" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="50dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/common_textview2" android:layout_width="100dp" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="@+id/common_textview" app:layout_constraintStart_toEndOf="@+id/common_textview" app:layout_constraintTop_toTopOf="@+id/common_textview" /> </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:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:id="@+id/common_textview" android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="50dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/common_textview2" android:layout_width="100dp" android:layout_height="0dp" android:layout_marginStart="70dp" app:layout_constraintBottom_toBottomOf="@+id/common_textview" app:layout_constraintStart_toEndOf="@+id/common_textview" app:layout_constraintTop_toTopOf="@+id/common_textview" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
其实很简单,只需要将控件自身的高度设置为0dp即可,0dp的意思就是match constraint,就是充满约束。
- 基于某个控件的下边界线居中
代码如下:<?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" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:background="#FFD115" android:id="@+id/common_textview" android:layout_width="match_parent" android:layout_height="100dp" android:layout_margin="50dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView app:layout_constraintStart_toStartOf="@id/common_textview" app:layout_constraintEnd_toEndOf="@id/common_textview" app:layout_constraintTop_toBottomOf="@id/common_textview" app:layout_constraintBottom_toBottomOf="@id/common_textview" android:background="@color/color_FFD115" android:id="@+id/common_textview2" android:layout_width="60dp" android:layout_height="50dp" /> </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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <View android:id="@+id/common_view" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintEnd_toStartOf="@id/common_view2" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/common_view2" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintEnd_toStartOf="@id/common_view3" app:layout_constraintStart_toEndOf="@id/common_view" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/common_view3" android:layout_width="100dp" android:layout_height="100dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/common_view2" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
控件宽度平分,只需要改变上述代码中的android:layout_width="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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/common_view"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintEnd_toStartOf="@id/common_view2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/common_view2"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintEnd_toStartOf="@id/common_view3"
app:layout_constraintStart_toEndOf="@id/common_view"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/common_view3"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/common_view2"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果图如下:
重点:让宽度为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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/common_view"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintHorizontal_weight="3"
app:layout_constraintEnd_toStartOf="@id/common_view2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
app:layout_constraintHorizontal_weight="2"
android:id="@+id/common_view2"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintEnd_toStartOf="@id/common_view3"
app:layout_constraintStart_toEndOf="@id/common_view"
app:layout_constraintTop_toTopOf="parent" />
<View
app:layout_constraintHorizontal_weight="1"
android:id="@+id/common_view3"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/common_view2"
app:layout_constraintTop_toTopOf="parent" />
</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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/view1" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" android:text="78" android:textSize="128sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView app:layout_constraintStart_toEndOf="@+id/view1" app:layout_constraintBaseline_toBaselineOf="@+id/view1" android:text="%" android:textSize="40sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@+id/view2" android:layout_marginTop="260dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" android:text="78" android:textSize="128sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView app:layout_constraintStart_toEndOf="@+id/view2" app:layout_constraintBottom_toBottomOf="@+id/view2" android:text="%" android:textSize="40sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
-
角度定位
使用角度定位需要3个条件:1.圆心 2.半径 3.角度。其中角度是从正上方顺时针开始的。
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/view_sun" android:layout_width="80dp" android:layout_height="80dp" android:src="@drawable/sun" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/view_earth" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/earth" app:layout_constraintCircle="@+id/view_sun" app:layout_constraintCircleAngle="45" app:layout_constraintCircleRadius="150dp" /> <ImageView android:id="@+id/view_moon" android:layout_width="20dp" android:layout_height="20dp" android:src="@drawable/moon" app:layout_constraintCircle="@+id/view_earth" app:layout_constraintCircleAngle="130" app:layout_constraintCircleRadius="30dp" /> </androidx.constraintlayout.widget.ConstraintLayout>
说明:
layout_constraintCircle
以哪个view为圆心
layout_constraintCircleRadius
圆的半径
layout_constraintCircleAngle
旋转角度, 以第一象限顺时针开始。效果如下:
角度定位 -
约束宽度
一个文本的长度不能超过图片的宽度。
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:background="@android:color/black" android:layout_height="match_parent"> <ImageView android:src="@drawable/sun" android:scaleType="fitXY" android:id="@+id/view1" android:layout_width="260dp" android:layout_height="80dp" android:layout_marginTop="50dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:layout_marginTop="10dp" android:textColor="@android:color/white" app:layout_constrainedWidth="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="文本很长很长文本很长很长文本很长很长文本很长很长文本很长很长文本很长很长" android:textSize="12sp" app:layout_constraintEnd_toEndOf="@+id/view1" app:layout_constraintStart_toStartOf="@+id/view1" app:layout_constraintTop_toBottomOf="@+id/view1" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
可以看到文本的整体的宽度被约束为和上面的图片等宽,高度的约束也是同理。
-
bias,约束倾向,取值范围:0.0-1.0。 0.0最左侧,1.0最右侧。一般配合约束宽度来使用。
看下聊天的UI效果如下:
聊天
文字短的时候包裹内容,超过最大宽度换行展示。
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <ImageView android:id="@+id/view1" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginTop="50dp" android:scaleType="fitXY" android:layout_marginStart="15dp" android:src="@drawable/sun" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:paddingTop="3dp" android:paddingBottom="3dp" android:paddingStart="2dp" android:paddingEnd="2dp" android:background="@android:color/holo_red_dark" android:layout_marginEnd="15dp" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0" app:layout_constrainedWidth="true" app:layout_constraintStart_toEndOf="@+id/view1" app:layout_constraintTop_toTopOf="@+id/view1" android:layout_marginStart="8dp" android:text="君不见,黄河之水天上来,奔流到海不复回。君不见,高堂明镜悲白发,朝如青丝暮成雪。人生得意须尽欢,莫使金樽空对月。" android:textColor="@android:color/white" android:textSize="16sp" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
-
短文字效果
短文字长度效果 -
中等文字效果
中等文字长度效果 -
超长文字效果
超长文字长度效果
水平方向上的约束倾向如上,垂直方向上的约束倾向同理。
- GoneMargin。当约束目标控件隐藏时,控件自身可以保留一定的间距。
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <ImageView android:visibility="gone" android:id="@+id/view1" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginTop="50dp" android:scaleType="fitXY" android:layout_marginStart="15dp" android:src="@drawable/sun" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView app:layout_goneMarginStart="30dp" android:paddingTop="3dp" android:paddingBottom="3dp" android:paddingStart="2dp" android:paddingEnd="2dp" android:background="@android:color/holo_red_dark" android:layout_marginEnd="15dp" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0" app:layout_constrainedWidth="true" app:layout_constraintStart_toEndOf="@+id/view1" app:layout_constraintTop_toTopOf="@+id/view1" android:layout_marginStart="8dp" android:text="君不见,黄河之水天上来,奔流到海不复回。君不见,高堂明镜悲白发,朝如青丝暮成雪。人生得意须尽欢,莫使金樽空对月。" android:textColor="@android:color/white" android:textSize="16sp" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
-
正常情况
GoneMargin1 - 当约束控件隐藏,但是不加
GoneMargin
属性。
GoneMargin2 - 当约束控件隐藏,加上
GoneMargin
属性。
GoneMargin3
可以看出来GoneMargin
的作用了吧。
-
约束链风格 ChainStyle
风格:packed(打包,组合),spread(扩散,默认),spread_inside(内部扩散)。而且约束链风格必须写在第一个控件上才有效。- 组件组合后居中
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <ImageView android:id="@+id/view1" android:layout_width="40dp" android:layout_height="40dp" android:scaleType="fitXY" android:src="@drawable/sun" app:layout_constraintVertical_chainStyle="packed" app:layout_constraintBottom_toTopOf="@+id/view2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/view2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_red_dark" android:paddingStart="2dp" android:paddingTop="3dp" android:paddingEnd="2dp" android:paddingBottom="3dp" android:text="君不见,黄河之水天上来,奔流到海不复回。" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/view1" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
垂直方向约束链风格
而且还支持约束倾向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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <View app:layout_constraintHorizontal_chainStyle="spread_inside" android:id="@+id/view1" android:layout_width="100dp" android:layout_height="200dp" android:background="@android:color/holo_red_dark" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/view2" app:layout_constraintStart_toStartOf="parent" /> <View android:id="@+id/view2" android:layout_width="100dp" android:layout_height="200dp" android:background="@android:color/holo_red_dark" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/view3" app:layout_constraintStart_toEndOf="@+id/view1" /> <View android:id="@+id/view3" android:layout_width="100dp" android:layout_height="200dp" android:background="@android:color/holo_red_dark" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/view2" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
spread_inside
垂直方向同理。
- 组件内部扩散
- 组件组合后居中
-
控件宽高比例保持一致, DimensionRatio
使用这个属性的前提是,控件的宽或者高至少有一个是充满约束的,即为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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <ImageView android:id="@+id/view1" android:layout_width="200dp" android:layout_height="0dp" app:layout_constraintDimensionRatio="2:1" android:background="@drawable/sun" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
宽高比:2:1
效果如下:
如果宽和高都是0dp,DimensionRatio需要加上“H,2:1”,这个H说明高度是计算出来的,也就是说宽度充满约束,这里就不再演示了。
- 百分比布局,宽度或者高度占parent的百分比
这个百分比始终是针对parent的百分比,而且使用百分比的前提是宽度或者高度必须充满约束,即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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <View android:background="@android:color/holo_red_dark" android:layout_width="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintWidth_percent="0.3" android:layout_height="320dp"/> <View android:background="@android:color/holo_green_dark" android:layout_width="0dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintWidth_percent="0.5" android:layout_height="320dp"/> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
第一个View 宽度占parent 的30%, 第二个View宽度占parent的50%,垂直方向上的百分比同理。
- GuideLine(基准线/辅助线)
这个是辅助控件,辅助控件之间的约束,而不是一个真正的控件。
下面举一个简单的UI栗子,比如登录页面。
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <androidx.constraintlayout.widget.Guideline android:id="@+id/guide_line" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.2" /> <TextView android:id="@+id/tv_username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="70dp" android:paddingTop="20dp" android:paddingBottom="20dp" android:text="用户名" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintEnd_toStartOf="@+id/guide_line" app:layout_constraintTop_toTopOf="parent" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:background="@android:color/white" android:hint="输入用户名" android:textColorHint="@android:color/black" app:layout_constraintBaseline_toBaselineOf="@id/tv_username" app:layout_constraintStart_toEndOf="@+id/guide_line" /> <TextView android:id="@+id/tv_password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="20dp" android:paddingBottom="20dp" android:text="密码" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintEnd_toStartOf="@+id/guide_line" app:layout_constraintTop_toBottomOf="@+id/tv_username" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:background="@android:color/white" android:hint="输入密码" android:textColor="@android:color/black" android:textColorHint="@android:color/black" app:layout_constraintBaseline_toBaselineOf="@+id/tv_password" app:layout_constraintStart_toEndOf="@+id/guide_line" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
- Group
当某一种状态下需要多好多控件进行隐藏和显示时,可以使用Group,来统一显示和隐藏。
代码如下:<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <androidx.constraintlayout.widget.Group android:id="@+id/group1" android:layout_width="wrap_content" android:visibility="gone" android:layout_height="wrap_content" app:constraint_referenced_ids="tv1,tv2" /> <androidx.constraintlayout.widget.Group android:id="@+id/group2" android:layout_width="wrap_content" android:layout_height="wrap_content" app:constraint_referenced_ids="tv3,tv4" /> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:padding="15dp" android:text="group1" android:textColor="@android:color/white" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" android:text="group1-2" android:textColor="@android:color/white" app:layout_constraintStart_toEndOf="@+id/tv1" app:layout_constraintTop_toTopOf="@+id/tv1" /> <TextView android:id="@+id/tv3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="30dp" android:layout_marginTop="80dp" android:padding="15dp" android:text="group2" android:textColor="@android:color/white" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" android:text="group2-1" android:textColor="@android:color/white" app:layout_constraintStart_toEndOf="@+id/tv3" app:layout_constraintTop_toTopOf="@+id/tv3" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
设置Group1的visibility=visible时,效果如下:
设置Group1的visibility=gone时,效果如下:
- Layer
也是一个约束辅助,它的使用和Group类似,只不过layer可以对整体进行旋转,平移等常用的操作。
代码如下:public class CommonTest extends FragmentActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.common_constraint_layout_demo); findViewById(R.id.layer).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //旋转45d° findViewById(R.id.layer).setRotation(45); //X轴向右平移100px findViewById(R.id.layer).setTranslationX(100); //Y轴向下平移100px findViewById(R.id.layer).setTranslationY(100); } }); } }
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="5dp" android:layout_marginTop="10dp" android:text="旋转" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.constraintlayout.helper.widget.Layer android:id="@+id/layer" android:layout_width="wrap_content" android:layout_height="wrap_content" app:constraint_referenced_ids="tv1,tv2,tv3,tv4" tools:ignore="MissingConstraints" /> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="15dp" android:layout_marginTop="10dp" android:background="@android:color/holo_blue_light" android:padding="10dp" android:text="text1" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_green_dark" android:padding="10dp" android:text="text2" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintStart_toEndOf="@+id/tv1" app:layout_constraintTop_toTopOf="@+id/tv1" /> <TextView android:id="@+id/tv3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="30dp" android:layout_marginTop="40dp" android:background="@android:color/darker_gray" android:padding="10dp" android:text="text3" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintStart_toStartOf="@+id/tv1" app:layout_constraintTop_toBottomOf="@+id/tv1" /> <TextView android:id="@+id/tv4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_purple" android:padding="10dp" android:text="text4" android:textColor="@android:color/white" android:textSize="16sp" app:layout_constraintStart_toEndOf="@+id/tv3" app:layout_constraintTop_toTopOf="@+id/tv3" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
- 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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" tools:context=".ui.CommonTest"> <androidx.constraintlayout.widget.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="end" app:constraint_referenced_ids="tv1,tv2" tools:ignore="MissingConstraints" /> <TextView android:id="@+id/tv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:text="文本1文本1文本1文本1文本1" android:textColor="@android:color/white" android:textSize="15sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:text="文本2文本2" android:textColor="@android:color/white" android:textSize="15sp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv1" /> <ImageView android:id="@+id/iv1" android:layout_width="25dp" android:layout_height="25dp" android:src="@drawable/moon" app:layout_constraintStart_toEndOf="@+id/barrier" app:layout_constraintTop_toTopOf="@+id/tv1" /> <ImageView android:id="@+id/iv2" android:layout_width="25dp" android:layout_height="25dp" android:src="@drawable/moon" app:layout_constraintStart_toEndOf="@+id/barrier" app:layout_constraintTop_toTopOf="@+id/tv2" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
像:Group,Layer,Barrier都是以ID的引用来实现的,所以如果使用了特殊的混淆工具,对id资源进行了混淆,这里就需要注意下,不然运行起来会找不到id的。
- Placeholder
占位符。
代码如下:public class CommonTest extends FragmentActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.common_constraint_layout_demo); } public void onClick(View view) { findViewById(R.id.placeholder).setContentId(view.getId()); } }
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black" tools:context=".ui.CommonTest"> <androidx.constraintlayout.widget.Placeholder android:id="@+id/placeholder" android:layout_width="50dp" android:layout_height="50dp" android:layout_marginTop="20dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/iv1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/sun" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/iv2" app:layout_constraintStart_toStartOf="parent" /> <ImageView android:id="@+id/iv2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/earth" app:layout_constraintEnd_toStartOf="@+id/iv3" app:layout_constraintStart_toEndOf="@+id/iv1" app:layout_constraintTop_toTopOf="@+id/iv1" /> <ImageView android:id="@+id/iv3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/moon" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/iv2" app:layout_constraintTop_toTopOf="@+id/iv1" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
当点击下面3个view其中一个view的时候,被点击的view会被替换到上面的Placeholder所在的位置。