前言
什么是約束布局(ConstraintLayout)
我們可以理解為增強版/升級版的相對布局(RelativeLayout)。
Android Studio 從版本2.3開始創(chuàng)建xml默認的根布局就是約束布局,相信大家對相對布局已經(jīng)是使用的非常6了,所有在使用約束布局的話就會比較輕松。
那么既然已經(jīng)有相對布局了,為什么還要用約束布局呢?最核心就是:
讓布局扁平化,減少布局嵌套的層次,提高渲染效率,提升應(yīng)用性能。
所以說約束布局還是很有必要學(xué)一學(xué)的,最起碼在性能優(yōu)化方面是很有幫助的。
下面就一起開始學(xué)習(xí)吧!
廢話不多說,直接進入主題。
舉個最簡單的栗子:
將一個在ConstraintLayout中居中,如下:

代碼很簡單,就是給TextView添加上下左右邊界的約束即可。所以寫約束布局就是寫控件的邊界約束。
下面我們先介紹下約束屬性的寫法以及含義。
app:layout_constraintStart_toStartOf="parent"
我們來解釋下屬性:
第一個start代表的是控件自身的約束方向。
第二個start代表的目標控件的約束方向。
第三個parent代表的是和那個控件建立約束。如果是父控件,就填parent,如果是其他控件,就填寫控件的id。
下面我們就以最實用的現(xiàn)實場景來簡單學(xué)習(xí)下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>
效果如下:

重點:讓控件自身的上邊界和先邊界分別和目標控件的上下邊界進行對應(yīng)約束即可。
- 垂直居中的同時,高度一致
<?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>
效果如下:

其實很簡單,只需要將控件自身的高度設(shè)置為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>
效果如下:

重點:控件自身的垂直約束方向都和目標控件的底邊建立約束即可。
- 權(quán)重平分空間
寬度相同,平分間距。
代碼如下:<?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"即可實現(xiàn)。
代碼如下:
<?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,充滿約束即可。
根據(jù)不同的權(quán)重實現(xiàn)不同比例的平分,這里的權(quán)重的使用必須是充滿約束才會生效,即寬度為0dp,而且約束布局的權(quán)重分為垂直和水平兩個方向。
代碼如下:
<?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>
效果圖如下:

這里只寫了水平方向上的權(quán)重,垂直方向上的權(quán)重同理。
- 不同大小文字的對齊(基準線對齊)
代碼如下:<?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旋轉(zhuǎn)角度, 以第一象限順時針開始。效果如下:
角度定位 -
約束寬度
一個文本的長度不能超過圖片的寬度。
代碼如下:<?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最左側(cè),1.0最右側(cè)。一般配合約束寬度來使用。
看下聊天的UI效果如下:
聊天
文字短的時候包裹內(nèi)容,超過最大寬度換行展示。
代碼如下:<?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="君不見,黃河之水天上來,奔流到海不復(fù)回。君不見,高堂明鏡悲白發(fā),朝如青絲暮成雪。人生得意須盡歡,莫使金樽空對月。" android:textColor="@android:color/white" android:textSize="16sp" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
-
短文字效果
短文字長度效果 -
中等文字效果
中等文字長度效果 -
超長文字效果
超長文字長度效果
水平方向上的約束傾向如上,垂直方向上的約束傾向同理。
- GoneMargin。當(dāng)約束目標控件隱藏時,控件自身可以保留一定的間距。
代碼如下:<?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="君不見,黃河之水天上來,奔流到海不復(fù)回。君不見,高堂明鏡悲白發(fā),朝如青絲暮成雪。人生得意須盡歡,莫使金樽空對月。" android:textColor="@android:color/white" android:textSize="16sp" /> </androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
-
正常情況
GoneMargin1 - 當(dāng)約束控件隱藏,但是不加
GoneMargin屬性。
GoneMargin2 - 當(dāng)約束控件隱藏,加上
GoneMargin屬性。
GoneMargin3
可以看出來GoneMargin的作用了吧。
-
約束鏈風(fēng)格 ChainStyle
風(fēng)格:packed(打包,組合),spread(擴散,默認),spread_inside(內(nèi)部擴散)。而且約束鏈風(fēng)格必須寫在第一個控件上才有效。- 組件組合后居中
代碼如下:<?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="君不見,黃河之水天上來,奔流到海不復(fù)回。" 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>效果如下:
垂直方向約束鏈風(fēng)格
而且還支持約束傾向bias.水平方向同理。
- 組件內(nèi)部擴散
代碼如下:
<?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
垂直方向同理。
- 組件內(nèi)部擴散
- 組件組合后居中
-
控件寬高比例保持一致, 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
當(dāng)某一種狀態(tài)下需要多好多控件進行隱藏和顯示時,可以使用Group,來統(tǒng)一顯示和隱藏。
代碼如下:<?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>
效果如下:
設(shè)置Group1的visibility=visible時,效果如下:

設(shè)置Group1的visibility=gone時,效果如下:

- Layer
也是一個約束輔助,它的使用和Group類似,只不過layer可以對整體進行旋轉(zhuǎn),平移等常用的操作。
代碼如下: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) { //旋轉(zhuǎn)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="旋轉(zhuǎn)" 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
屏障,柵欄。給約束控件設(shè)置約束上的屏障,已達到約束位置的目的。
代碼如下:<?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的引用來實現(xiàn)的,所以如果使用了特殊的混淆工具,對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>
效果如下:

當(dāng)點擊下面3個view其中一個view的時候,被點擊的view會被替換到上面的Placeholder所在的位置。









