作者:小立子
來源:https://juejin.cn/post/6844903764462141447
該篇文章的主旨是幫助開發者了解ConstraintLayout的基本使用方法以及在日常開發項目中的使用場景的說明
ConstraintLayout官方文檔ConstraintLayout是一個ViewGroup,允許你靈活的指定子View的位置和大小(具體多靈活在下面的場景中進行說明),官方文檔中說明ConstraintLayout的特性有以下幾種:
Relative positioning - 相對位置
Margins - 邊距
Centering positioning - 位置居中
Visibility behavior - 可見性行為
Dimension constraints - 尺寸限制
Chains - 鏈
Virtual Helpers objects - 虛擬幫助對象(Guideline)
Optimizer - 優化
以上幾個特性部分有點抽象,官方文檔中也對每一個特性都進行了詳細的說明和舉例,有意者可以單獨去查閱,ConstraintLayout
,
在下面的應用場景中也會穿插說明。對於開發者來說,主要了解使用場景和在項目中如何使用,用得多了就對該控制項有了比較深入的了解。再看文檔會更容易理解。畢竟文檔是英文的。
在沒有ConstraintLayout之前我們寫布局一般使用到的布局就是 相對布局 和 線性布局
,相對布局中控制項的位置都是基於另一個控制項的位置,這個和ConstraintLayout有一絲相似之處,線性布局就是直接以瀑布流的形式進行布局。
ConstraintLayout 根據字面意思了解為約束布局,所以,所以在寫布局文件的時候, 需要對每一個控制項進行約束
,對每一個顯示在約束布局中的內容進行約束,約束其大小,位置。下面介紹一下約束布局的相關屬性和使用。
決定視圖的大小和位置可以由View四個邊來確定, left top right bottom ,
所以約束布局可以通過對四個邊的約束來達到實際布局效果,相關四個邊的屬性有,如:
1app:layout_constraintLeft_toLeftOf
2app:layout_constraintLeft_toRightOf
3app:layout_constraintRight_toLeftOf
4app:layout_constraintRight_toRightOf
5app:layout_constraintTop_toTopOf
6app:layout_constraintTop_toBottomOf
7app:layout_constraintBottom_toTopOf
8app:layout_constraintBottom_toBottomOf
9app:layout_constraintStart_toEndOf
10app:layout_constraintStart_toStartOf
11app:layout_constraintEnd_toStartOf
12app:layout_constraintEnd_toEndOf
應該根據這些屬性的名稱就能了解它們的作用,下面舉例說明:比如實現一個登陸界面,兩個文本框和一個按鈕。
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent">
7
8 <EditText
9 android:id="@+id/edt_username"
10 android:layout_width="0dp"
11 android:layout_height="50dp"
12 android:layout_marginStart="25dp"
13 android:layout_marginTop="200dp"
14 android:layout_marginEnd="25dp"
15 android:hint="請輸入用戶名"
16 android:inputType="text"
17 app:layout_constraintEnd_toEndOf="parent"
18 app:layout_constraintStart_toStartOf="parent"
19 app:layout_constraintTop_toTopOf="parent" />
20
21 <EditText
22 android:id="@+id/edt_password"
23 android:layout_width="0dp"
24 android:layout_height="wrap_content"
25 android:layout_marginTop="25dp"
26 android:hint="請輸入密碼"
27 android:inputType="textPassword"
28 app:layout_constraintEnd_toEndOf="@id/edt_username"
29 app:layout_constraintStart_toStartOf="@id/edt_username"
30 app:layout_constraintTop_toBottomOf="@id/edt_username" />
31
32 <Button
33 android:id="@+id/btn_login"
34 android:layout_width="0dp"
35 android:layout_height="wrap_content"
36 android:layout_marginTop="30dp"
37 android:text="登 錄"
38 app:layout_constraintEnd_toEndOf="@id/edt_password"
39 app:layout_constraintStart_toStartOf="@id/edt_password"
40 app:layout_constraintTop_toBottomOf="@id/edt_password" />
41</androidx.constraintlayout.widget.ConstraintLayout>
很簡單的一個頁面,如果用LinearLayout更快,但是ConstraintLayout本身就是為了解決複雜布局而生的,在日常開發中的需求可能會讓你各種嵌套布局,但是ConstraintLayout基本上都是一個布局就可以ok,所以只有你了解後才知道使用有多得勁,現在簡單的分析說明下上面的布局原理。
1.確定用戶名EditText的位置和大小,從四個邊來約束,首先約束top,使用top_toTopOf="parent"將用戶名EditText的頂部和父布局的頂部關聯起來,然後通過marginTop來增加邊距,如果不設置top_toTopOf屬性,marginTop屬性是不起作用的,任何沒有增加約束的
邊
設置margin屬性都是不起作用的,上面的代碼中我們將EditText的width設置為0dp,然後給左右兩邊分別增加了約束,約束到父布局的start和end,通過以上三個屬性,就確定了該EditText的位置和大小。
2.確定了用戶名EditText的位置之後,進行添加密碼EditText,和上一個EditText類似,增加左右上三邊的約束,不同的是top_toTopOf屬性的值改為了edt_username,不在把約束添加到parent,而是添加到用戶名的EditText,這樣密碼EditText就顯示到用戶名的下面了。登錄同理
只需要記住,ConstraintLayout中的所有空間添加上 左上右下 四個邊的約束,就能確定空間的位置(對應了開始說的 Relative positioning 和 Margins 兩個特性) ,記住這個就掌握使用的一大半了
控制項居中想讓控制項居中也很簡單,比如說上面的登錄按鈕,不想要那麼大,可以將控制項的width屬性改成wrap_content,這樣控制項就直接居中了。
在給控制項添加完約束之後,如果width或者height給的值為0,則控制項的大小將完全按照約束的大小進行展示,如果設置了wrap_content,則控制項會居中顯示
該約束是針對文本相關控制項添加的,比如要再添加一個註冊按鈕在登錄的右側
1 <Button
2 android:id="@+id/btn_login"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content"
5 android:layout_marginTop="30dp"
6 android:text="登 錄"
7 app:layout_constraintEnd_toStartOf="@id/btn_sign_up"
8 app:layout_constraintHorizontal_chainStyle="spread"
9 app:layout_constraintStart_toStartOf="@id/edt_password"
10 app:layout_constraintTop_toBottomOf="@id/edt_password" />
11
12 <Button
13 android:id="@+id/btn_sign_up"
14 android:layout_width="wrap_content"
15 android:layout_height="wrap_content"
16 android:text="註冊"
17 app:layout_constraintBaseline_toBaselineOf="@id/btn_login"
18 app:layout_constraintHorizontal_chainStyle="spread"
19 app:layout_constraintStart_toEndOf="@id/btn_login"
20 app:layout_constraintEnd_toEndOf="@id/edt_password"
21 app:layout_constraintTop_toBottomOf="@id/edt_password" />
在上面的註冊控制項中,增加了layout_constraintBaseline_toBaselineOf屬性,依賴登錄按鈕,這樣他們的繪製基線就在同一y軸上了,從而達到對齊的效果。
在上面的基線約束中,可能你會發現登錄和註冊的位置非常對稱,這個就是chains約束,對於chains約束只說明兩點,你就會輕鬆使用了。
例如上面的登錄和註冊兩個按鈕,登錄的右邊距約束必須添加到註冊的左邊距上,即:登錄的 end_ToStartOf="btn_sign_up",註冊的
start_toEndOf="btn_login",如果是多個控制項一樣,一個控制項的結束依賴到另一個的開始。這是水平chain , 垂直的桶裡
layout_constraintDimensionRatio
尺寸約束的使用不多,但是這個屬性很重要,在很多的場景中可以使用該約束,先對屬性進行說明,應用場景後面再說。了解了作用,自然就能在實際開發中找到場景。比如說我們要實現一個ImageView的寬是高的2倍,可能有人想,我把寬固定了那高除以2不就出來了嘛,當然可以,但是有些場景,比如說寬是屏幕的寬度,match_parent呢,用尺寸約束就可以很輕鬆的達到效果。
1 <ImageView
2 android:layout_width="0dp"
3 android:layout_height="0dp"
4 app:layout_constraintStart_toStartOf="parent"
5 app:layout_constraintEnd_toEndOf="parent"
6 app:layout_constraintTop_toTopOf="parent"
7 app:layout_constraintDimensionRatio="2:1"
8 android:background="@color/colorAccent"
9 />
這樣就比較輕鬆的實現了高是寬的2倍,在什麼機型上都是。
百分比約束layout_constraintHeight_percent
layout_constraintWidth_percent
分別對寬高進行百分比約束。
1 <ImageView
2 android:layout_width="0dp"
3 android:layout_height="0dp"
4 app:layout_constraintStart_toStartOf="parent"
5 app:layout_constraintEnd_toEndOf="parent"
6 app:layout_constraintTop_toTopOf="parent"
7 app:layout_constraintHeight_percent="0.2"
8 app:layout_constraintWidth_percent="0.5"
9 android:background="@color/colorAccent"
10 />
百分比約束相對很實用,但是比較少用,很類似之前LinearLayout的weight權重。
Visibility behavior可見性行為的屬性包括:
1layout_goneMarginStart
2layout_goneMarginEnd
3layout_goneMarginLeft
4layout_goneMarginTop
5layout_goneMarginRight
6layout_goneMarginBottom
比如說上面的登錄頁面,如果程序中設置了用戶名EditText設置了setVisible(false),那麼密碼EditText就會直接到頂部了,甚至造成布局錯亂,為什麼?應為密碼EditText的左右約束添加到了用戶名的EditText上,如果想讓用戶名EditText隱藏的時候密碼EditText和top右邊距,就可以給密碼EditText加上goneMarginTop屬性,
為了防止因為控制項隱藏造成布局錯亂,在已知一些控制項會隱藏的前提下,其他的控制項不要左右邊依賴可能會隱藏的視圖,防止布局錯亂
比如上面的為了防止用戶名EditText隱藏造成密碼EditText顯示不了的問題,可以給密碼EditText的左右依賴添加到父布局即可。
guideline也是一個控制項,但是這個控制項是只在約束布局中才能起作用的 輔助控制項
,是幫助輔助布局的,比如說,我們添加一個GuideLine,將屏幕平分為兩半,一個視圖在左,一個在右。拿上面的登錄註冊兩個按鈕來說,上面的實現方式是增加了chain約束,也可以用GuideLine來實現。代碼如下:
1 <androidx.constraintlayout.widget.Guideline
2 android:id="@+id/guideline"
3 android:layout_width="wrap_content"
4 android:layout_height="wrap_content"
5 android:orientation="vertical"
6 app:layout_constraintGuide_percent="0.5" />
7
8 <Button
9 android:id="@+id/btn_login"
10 android:layout_width="wrap_content"
11 android:layout_height="wrap_content"
12 android:layout_marginTop="30dp"
13 android:text="登 錄"
14 app:layout_constraintEnd_toStartOf="@id/guideline"
15 app:layout_constraintStart_toStartOf="@id/edt_password"
16 app:layout_constraintTop_toBottomOf="@id/edt_password" />
17
18 <Button
19 android:id="@+id/btn_sign_up"
20 android:layout_width="wrap_content"
21 android:layout_height="wrap_content"
22 android:text="註冊"
23 app:layout_constraintBaseline_toBaselineOf="@id/btn_login"
24 app:layout_constraintEnd_toEndOf="@id/edt_password"
25 app:layout_constraintStart_toEndOf="@id/guideline" />
中間的虛線,即為增加的輔助GuideLine控制項,該控制項需要設置兩個屬性,第一是設置orientation屬性,垂直或者水平,第二是百分比
layout_constraintGuide_percent,添加好輔助視圖之後,其他控制項就可以依賴於它進行布局。
以上幾方面就是在日常開發中的基礎使用相關介紹,掌握了這些基本上都能滿足開發的需求,下面說下ConstraintLayout的使用場景
使用場景以前我們在實現布局的時候經常各種嵌套,現在不帶滾動的布局,都可以只用一個父布局就可以解決,減少了布局的層級深度
在NestedScrollView中嵌套一個ConstraintLayout即可。
以前item布局也是各種嵌套布局,有了ConstraintLayout之後發現真的是省事了很多,代碼看起來也比較舒服
像有一些banner圖的設計尺寸都是固定的,我們只需要寬度設置全屏,然後設置寬高比,就能適配所有屏幕,等等。。妙用很多,實際開發自己發掘。
總之如果在使用ConstraintLayout看了該內容哪裡不對希望評論補充,或者不對的地方糾正我一下,如果是沒有用過的,希望你趕緊用起來,省時省力
如果你覺得對你有所幫助,可以關注我的微信公眾號 程式設計師徐公
Android 啟動優化(一) - 有向無環圖
Android 啟動優化(五)- AnchorTask 1.0.0 版本正式發布了
什麼?Android webView 的字體突然變小了