A ConstraintLayout is a android.view.ViewGroup which allows you to position and size widgets in a flexible wayandroid
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
bash
約束佈局做爲Google大力推廣的佈局方式,可謂集萬千寵愛於一身:app
缺點就是,用了約束佈局以後,再也切不回之前的佈局方式了,重度依賴。ide
TODO: 2.0的自定義Helper和motionLayout還未明白,先不記錄,後期學完再補進來。佈局
從名字上看,可能大體明白其對齊方式(就是自身的哪一邊對齊目標view的哪一邊),就不詳細列出所有了。性能
ConstraintLayout | 對齊方式 |
---|---|
app:layout_constraintStart_toStartOf | 自身左邊與目標左邊對齊 |
app:layout_constraintStart_toEndOf | 自身左邊與目標右邊對齊 |
... | ... |
對於約束佈局的定位對齊方式,能夠將其想象成高中物理的拉力。app:layout_constraintStart_toStartOf
表示自身的左邊被目標view的左邊拉住;app:layout_constraintEnd_toEndOf
表示自身的右邊被目標view的右邊拉住flex
假設一個button要在父佈局居中顯示,則只須要它的上下左右被父佈局的上下左右拉住便可:ui
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我要居中顯示"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
複製代碼
約束佈局還提供了一個設置偏移量的功能。好比,如今居中顯示煩了,要往左邊靠一點。能夠理解爲左邊的拉力我要大一點,則能夠經過設置bias來實現。spa
...
app:layout_constraintHorizontal_bias="0.2"
...
複製代碼
設置margin與以前方式同樣,都是android:layout_marginXXX
,不一樣的是,要使margin生效,必須有同一方向上的約束拉力。即要marginBottom就必須有一個app:layout_constraintBottom_toXXXOf
.net
約束佈局下,不使用MATCH_PARENT
,保留WRAP_CONTENT
,同時還可使用約束佈局特有的三種大小設置模式:spread,wrap,percent;三者能夠經過app:layout_constraintWidth_default
或app:layout_constraintHeight_default
設置。
注:使用約束佈局的大小設置,須要先將要設置的寬或高指定爲0dp
app:layout_constraintXXX_default="spread"
,是默認的,表示在約束條件下的最大尺寸;
一樣能夠將其想象成拉力,假設view寬爲0dp,左邊與ViewA右邊對齊,右邊與ViewB左邊對齊,則左邊會被拉伸至ViewA的右邊,右邊會被拉伸至ViewB的左邊:(下面的圖爲了顯示清楚,故意加了margin)
...
<TextView
android:id="@+id/viewA"
android:layout_width="100dp"
android:layout_height="100dp"
android:gravity="center"
android:textSize="20sp"
android:text="ViewA"
android:textColor="@android:color/white"
android:background="@android:color/holo_red_dark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/viewB"
android:layout_width="100dp"
android:layout_height="100dp"
android:gravity="center"
android:textSize="20sp"
android:text="viewB"
android:textColor="@android:color/white"
android:background="@android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:layout_width="0dp"
android:layout_height="100dp"
android:text="我要被拉伸"
android:textSize="20sp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
app:layout_constraintStart_toEndOf="@id/viewA"
app:layout_constraintEnd_toStartOf="@id/viewB"
app:layout_constraintTop_toTopOf="parent"
/>
...
複製代碼
app:layout_constraintWidth_default="wrap"
:自適應大小,但不超過約束條件下的最大尺寸。
仍是上面的例子,若是是傳統的WRAP_CONTENT
,當內容較大時,會直接超過約束條件,如圖:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拉伸我要被要被拉伸我要被拉伸"
android:textSize="20sp"
app:layout_constraintWidth_default="wrap"
app:layout_constraintStart_toEndOf="@id/viewA"
app:layout_constraintEnd_toStartOf="@id/viewB"
app:layout_constraintTop_toTopOf="parent"
/>
複製代碼
當指定爲wrap模式,則會保留約束條件:
...
android:layout_width="0dp"
app:layout_constraintWidth_default="wrap"
...
複製代碼
另外,針對傳統的WRAP_CONTENT
模式,約束佈局有額外的屬性,使得它也能保留約束條件:app:layout_constrainedWidth="true"
此時與wrap模式同樣的效果。
app:layout_constraintWidth_default="percent"
:以父佈局的百分比做爲自身的大小,即百分比佈局。(利用次特性可解決部分常見適配),經過app:layout_constraintWidth_percent
設置比例大小,0f-1.0f
...
android:layout_width="0dp"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.8"
...
複製代碼
app:layout_constraintDimensionRatio
:約束佈局還能夠指定view自身寬高比例。
其值能夠爲「width:height」或者「width/height」,如寬是高的2倍:app:layout_constraintDimensionRatio="2:1"
或app:layout_constraintDimensionRatio="2"
要使其生效的話,必須將對應的寬或高設置爲0dp。例如寬爲0dp,高爲10dp,app:layout_constraintDimensionRatio=2:1
以後,寬最終爲20dp;
若是寬高兩項都爲0dp的話,則最終尺寸會設置爲符合約束的最大尺寸,同時保持設置的比例。這樣有時結果不是咱們所想要的,咱們能夠指定寬或高(H,W)哪一邊約束條件來肯定尺寸,哪一邊經過比例來肯定尺寸;
如app:layout_constraintDimensionRatio="W,2:1"
則指明寬按照比例來計算最終尺寸,而高則根據約束條件;app:layout_constraintDimensionRatio="H,2:1"
則相反。可自行體驗下。
這個就和屬性名稱同樣的意思啦:
app:layout_constraintHeight_min
app:layout_constraintWidth_min
app:layout_constraintHeight_max
app:layout_constraintWidth_max
鏈式佈局是約束佈局經常使用的另外一個強大功能,能夠快速實現等分佈局等,還能夠實現相似LinearLayout佈局的weight比重功能。
約束鏈具備三種模式:
(gif是在medium上看到的,原連接一會兒沒找到)
約束鏈具備水平方向和垂直方向的。
將多個view構建成一個水平方向的鏈,則須要多個view在水平方向上兩兩約束
<ImageView
android:id="@+id/img1"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img1"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/img2"
android:layout_marginTop="20dp"
/>
<ImageView
android:id="@+id/img2"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img2"
android:scaleType="centerCrop"
app:layout_constraintStart_toEndOf="@id/img1"
app:layout_constraintTop_toTopOf="@id/img1"
app:layout_constraintEnd_toStartOf="@+id/img3"
/>
<ImageView
android:id="@+id/img3"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img3"
android:scaleType="centerCrop"
app:layout_constraintStart_toEndOf="@id/img2"
app:layout_constraintTop_toTopOf="@id/img1"
app:layout_constraintEnd_toEndOf="parent"
/>
複製代碼
這就建成了一條水平線上的約束鏈。垂直方向上的也相似,保持view 之間在垂直方向上兩兩約束便可。
鏈的第一個view,即img1,稱爲鏈頭。在鏈頭上設置app:layout_constraintHorizontal_chainStyle
或app:layout_constraintVertical_chainStyle
可分別設置水平或垂直鏈的模式。
app:layout_constraintVertical_chainStyle="spread"
複製代碼
app:layout_constraintHorizontal_weight
/app:layout_constraintVertical_weight
分別設置水平和垂直鏈上的權重
注意:要使其生效,必須將大小指定爲0dp
<ImageView
android:id="@+id/img1"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintHorizontal_weight="1"
...
/>
<ImageView
android:id="@+id/img2"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintHorizontal_weight="2"
...
/>
<ImageView
android:id="@+id/img3"
android:layout_width="0dp"
android:layout_height="100dp"
app:layout_constraintHorizontal_weight="2"
...
/>
複製代碼
約束佈局還提供一種炫酷的圓形佈局:能夠以角度和距離約束某個view中心相對於另外一個view的中心。
實際開發沒怎麼用過,實現相似鐘錶效果就很不錯。
app:layout_constraintCircle
: 圓心,值是某個view的id
app:layout_constraintCircleRadius
: 半徑
app:layout_constraintCircleAngle
:角度,值是從0-360,0是指整上方
<ImageView
android:id="@+id/img4"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img3"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<ImageView
android:id="@+id/img5"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img5"
android:scaleType="centerCrop"
app:layout_constraintCircle="@id/img4"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="180dp"
/>
複製代碼
約束佈局還提供了一系列組件使得能夠更靈活地佈局。如Group能夠同時控制一堆view的可見性,GuideLine能夠虛擬一條輔助線等等。
Group是一個虛擬視圖,能夠經過把viewapp:constraint_referenced_ids
放到裏面,統一同時控制這些view的可見性。
<androidx.constraintlayout.widget.Group
android:id="@+id/mGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="img1,img2"
/>
複製代碼
Group也是繼承自view的,直接在代碼中像普通view同樣設置可見性,就能同時控制到img1,img2的可見性了。
mGroup.visibility = View.VISIBLE
複製代碼
Guideline至關於一條虛擬輔助線,可分爲水平、垂直線,幫助定位的。
考慮一個需求,兩個view,要在屏幕中間一左一右,如果傳統定位,就弄一個線性佈局放兩個view,而後再把這個線性佈局居中。使用約束佈局,能夠在屏幕正中間放一條虛擬垂直輔助線,而後兩個view分別放在這條線左右便可。
android:orientation
設置垂直仍是水平app:layout_constraintGuide_percent
經過百分比設置位置,取值能夠是0f-1.0f或0%-100%app:layout_constraintGuide_begin
設置相對start/top的偏移量,dpapp:layout_constraintGuide_end
設置相對end/bottom的偏移量,dp<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5"
/>
<ImageView
android:id="@+id/img1"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img1"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline"
android:layout_marginTop="20dp"
android:layout_marginEnd="50dp"
/>
<ImageView
android:id="@+id/img2"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img2"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline"
android:layout_marginTop="20dp"
android:layout_marginStart="50dp"
/>
複製代碼
Barrier能夠獲取多個約束view的邊界。能夠得到所包含的多個view的最左最右等邊界。
考慮這樣一個需求,左邊是text1和text2,另外有一個view,必須放在這兩個text的右邊
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="text1"
android:background="@android:color/black"
android:textColor="@android:color/white"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="10dp"
/>
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="text2"
android:background="@android:color/holo_red_dark"
android:textColor="@android:color/white"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text1"
android:layout_marginTop="20dp"
/>
<ImageView
android:id="@+id/img1"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img1"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="@id/text1"
app:layout_constraintBottom_toBottomOf="@id/text2"
app:layout_constraintStart_toEndOf="@id/text1"
android:layout_marginStart="50dp"
/>
複製代碼
由於img1只能有一個描點,因此以text1爲約束點。但text一、text2寬度時動態的,當text2文本過長時,會發生遮擋。
此時barrier就派上用場了,它能夠動態獲取text一、text2的最右側,這樣只要img1依賴改成Barrier的最右側,就能夠解決問題了
app:barrierDirection
,取值有top、bottom、left、right、start、end,用於設置獲取的是哪側,好比上面的例子,獲取的是最右側start/right。app:constraint_referenced_ids
設置須要包含的view的id...
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="text1,text2"
app:barrierDirection="end"
/>
<ImageView
android:id="@+id/img1"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img1"
android:scaleType="centerCrop"
app:layout_constraintTop_toTopOf="@id/text1"
app:layout_constraintBottom_toBottomOf="@id/text2"
app:layout_constraintStart_toEndOf="@id/barrier"
android:layout_marginStart="50dp"
/>
...
複製代碼
約束佈局2.0增長了Layer、State、Flow等高效率組件,因文章篇幅,下一篇補上。