ConstraintLayout 的簡介
1.ConstraintLayout,中文稱約束佈局,在2016年Google I/O大會時提出,2017年2月釋出正式版,目前穩定版本為1.0.2。約束佈局作為Google今後主推的佈局樣式,可以完全替代其他佈局,降低頁面佈局層級,提升頁面渲染效能。
2.ConstraintLayout的優劣
優點:當佈局出現多層巢狀的時候,使用ConstraintLayout可以減少佈局巢狀,平時我們基本都是用LinearLayout和RelativeLayout,一層LinearLayout巢狀會導致onMeasure測量兩次,而RelativeLayout是四次,雖然我們感覺不到,為了更好就要專案效能和提升自我,有必要去學習一下。另外一點ConstraintLayout也向下相容到API 9,所以你再也沒有理由不用了。
缺點:當佈局沒巢狀的時候,ConstraintLayout要想實現一些效果需要設定太多的屬性,相對於個人來說比較繁瑣。
3.如果使用以及要求
第一步:在project的build.gradle設定谷歌的遠端倉庫
repositories {
maven {
url `https://maven.google.com`
}
}
複製程式碼
第二步:在要使用ConstraintLayout的module的build.gradle檔案中引入約束佈局庫
dependencies {
compile `com.android.support.constraint:constraint-layout:1.0.2`
}
複製程式碼
ConstraintLayout 屬性介紹
####相對位置屬性
layout_constraintTop_toTopOf — 期望檢視的上邊對齊另一個檢視的上邊。
layout_constraintTop_toBottomOf — 期望檢視的上邊對齊另一個檢視的底邊。
layout_constraintTop_toLeftOf — 期望檢視的上邊對齊另一個檢視的左邊。
layout_constraintTop_toRightOf — 期望檢視的上邊對齊另一個檢視的右邊。
layout_constraintBottom_toTopOf — 期望檢視的下邊對齊另一個檢視的上邊。
layout_constraintBottom_toBottomOf — 期望檢視的底邊對齊另一個檢視的底邊。
layout_constraintBottom_toLeftOf — 期望檢視的底邊對齊另一個檢視的左邊。
layout_constraintBottom_toRightOf — 期望檢視的底邊對齊另一個檢視的右邊。
layout_constraintLeft_toTopOf — 期望檢視的左邊對齊另一個檢視的上邊。
layout_constraintLeft_toBottomOf — 期望檢視的左邊對齊另一個檢視的底邊。
layout_constraintLeft_toLeftOf — 期望檢視的左邊對齊另一個檢視的左邊。
layout_constraintLeft_toRightOf — 期望檢視的左邊對齊另一個檢視的右邊。
layout_constraintRight_toTopOf — 期望檢視的右邊對齊另一個檢視的上邊。
layout_constraintRight_toBottomOf — 期望檢視的右邊對齊另一個檢視的底邊。
layout_constraintRight_toLeftOf — 期望檢視的右邊對齊另一個檢視的左邊。
layout_constraintRight_toRightOf — 期望檢視的右邊對齊另一個檢視的右邊。
複製程式碼
以上屬性都是設定當前控制元件相對控制元件的位置關係,以layout_constraintLeft_toLeftOf=@id/btn_A為例子,其中layout_部分是固定格式,分為兩部分,第一部分constraintLeft是表示當前控制元件的左邊界,toLeftOf代表就是當前控制元件在btn_A的左邊,app:layout_constraintBaseline_toBaselineOf=”@id/btn_A” 這個比較特殊,這個相當於當前的控制元件的水平中心線與btn_A的水平中心線為準,下面是例子
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_relative_position"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.RelativePositionActivity">
<Button
android:id="@+id/btn_A"
android:text="A"
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_constraintBottom_toBottomOf="parent"
/>
<Button
android:text="在A下方,與A左對齊"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="@id/btn_A"
android:layout_marginTop="32dp"
/>
<Button
android:text="在A上方,與A居中對齊"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="@id/btn_A"
app:layout_constraintRight_toRightOf="@id/btn_A"
android:layout_marginBottom="32dp"
/>
<Button
android:text="baseline對齊"
android:layout_width="wrap_content"
android:layout_height="80dp"
app:layout_constraintBaseline_toBaselineOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="8dp"
android:gravity="bottom"
/>
<Button
android:text="水平居中對齊"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:gravity="bottom"
app:layout_constraintTop_toTopOf="@id/btn_A"
app:layout_constraintBottom_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toRightOf="@id/btn_A"
android:layout_marginLeft="16dp"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
相對位置的總結:
- 一個控制元件一般只需要相對於一個控制元件設定相對位置,與Java的單繼承相似,除了連結串列結構,後面會提到
- 設定app:layout_constraintBaseline_toBaselineOf=”@id/btn_A”屬性之後
再設定上下位置的約束無效,設定左右的約束屬性還是有效的
####偏移屬性(BIAS)
在設定控制元件的居中屬性之後,通過偏移屬性可以設定讓控制元件更偏向於依賴控制元件的某一方,偏移設定為0~1之間的值。相應屬性:
- layout_constraintHorizontal_bias // 水平偏移
- layout_constraintVertical_bias // 垂直偏移
舉個例子:
<Button
android:text="水平偏移30%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3"
/>
複製程式碼
這個例子是最上面哪個水平偏移30%的
關於偏移屬性的總結:
- 設定偏移之前一定要設定一個相對位置,如果沒有相對位置,偏移時無效的
- 設定的相對位置一定要是 ,app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintRight_toRightOf=”parent” - 水平方向的一定要先設定app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintRight_toRightOf=”parent”
垂直方向的一定要設定app:layout_constraintTop_toTopOf=”parent”
app:layout_constraintBottom_toBottomOf=”parent” - 偏移值預設從0-1的數字,當然也可以設定負數和大於1的數字,但是效果就是顯示在螢幕外
- 水平偏移量是螢幕寬度的偏移倍數,垂直偏移時螢幕高度的偏移倍數
####可見性屬性(VISIBILITY)
#####(一)
當控制元件設定GONE的時候,雖然控制元件GONE了,但是控制元件之間的約束條件還在
例子如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="@+id/activity_bias"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:visibility="gone"
android:id="@+id/btn_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_marginLeft="16dp"
android:gravity="center"
android:text="與A水平居中對齊"
app:layout_constraintBottom_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toRightOf="@id/btn_A"
app:layout_constraintTop_toTopOf="@id/btn_A" />
</android.support.constraint.ConstraintLayout>
複製程式碼
效果
#####(二)
控制元件設定為GONE的時候,也可以設定GONE之後的app:layout_goneMarginLeft=”100dp” ,有些時候想實現特殊效果可以使用
####尺寸約束
- minWidth :最小寬度,即使沒有內容時也要佔有minWidth 的寬度,前提是寬度屬性android:layout_width=”wrap_content” ,當內容的時候寬度大於minWidth 時,控制元件寬度自動擴充
- 填充模式:類似LinearLayout 的android:layout_weight=”1″屬性,區別就是,如果想水平方向最大填充,設定android:layout_width=”0dp”,一定要設定,否則無效,同理垂直方向。
- constrainedWidth:constrainedWidth有兩個值,當為true的時候就開啟了控制元件的最小寬度或者高度,否則相反,配合layout_constraintWidth_min屬性設定最小寬度,需要注意的是,當屬性中存在minWidth 時,這個屬性是失效的,以minWidth 為準
- 百分比佈局:首先必須要設定app:layout_constraintWidth_default=”percent”
app:layout_constraintHeight_default=”percent”這兩個屬性 ,還有android:layout_width=”0dp”
android:layout_height=”0dp”屬性,否則之後設定的都是無效的, app:layout_constraintWidth_percent=”0.5″
app:layout_constraintHeight_percent=”0.3″設定這兩個就可以實現相對於螢幕的百分比寬高了
####控制元件寬高比(RATIO)
這個對於我們開發者簡直就是福利,如果是動態設定寬高相對麻煩。
layout_constraintDimentionRatio屬性代表設定控制元件寬高的比例,前提是控制元件的寬高必須有一個設定為0dp,否則不去作用
- 第一種方式:直接設定一個float值,表示寬高比,記住是寬高比,寬高比!!!
app:layout_constraintDimensionRatio="2"
複製程式碼
- 第二種方式:使用比值,例如 :
app:layout_constraintDimensionRatio="16:9"
或者
app:layout_constraintDimensionRatio="H,16:9"
複製程式碼
這種方式,如果沒有字首就代表是寬高比,如果加了字首H代表比值的第一個數字是高度,W是寬度
說明:這裡面坑很多,這裡就一一簡單的介紹一下,如果寬高都設定的屬性為0dp,首先螢幕高度肯定大於寬度,所以寬度上面一定處於填充狀態,這0-1之間有個值正好是螢幕寬高比,這時候控制元件正好填充螢幕,如果想不想寬度被填充至少要保證寬高其中一個屬性的值不為0dp,只要有一個屬性不為0dp的時候,這時候比例的根據就是內容的填充寬高來定而不是螢幕。當寬高兩個值都不為0dp的時候,這時候比例屬性無效。並且這個比例會自動計算內容是否需要換行展示更好的比例,所以非常智慧。
####鏈式約束(CHAIN)
鏈這個概念是約束佈局新提出的,它提供了在一個維度(水平或者垂直),管理一組控制元件的方式。
處於水平或者垂直方向第一個控制元件為chain head(鏈頭),當我們給chain head設定layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle,整條鏈的狀態將會發生改變。
-
CHAIN_SPREAD – 元素之間的空間將會均勻分佈,這是系統預設的排列方式
-
CHAIN_SPREAD – 首尾的兩條鏈將不會分配空間,其餘內部的鏈將均勻分配空間。
-
CHAIN_PACKED – 首尾兩條鏈將會分配空間,鏈內部將不會分配空間
-
Weight 通過設定的weight值來分配元素的寬或者高
注意:
-
layout_constraintHorizontal_chainStyle屬性值是小寫的,文件裡給出的是大寫的。
-
weight樣式的實現有一個前提,chainStyle必須為預設的spread樣式
-
設定Weight樣式時記得把元素中的寬或者設定成0dp
Guideline
首先說明一下,Guideline只能用於ConstraintLayout中,是一個工具類,不會被顯示,僅僅用於輔助佈局。
它可以是horizontal或者 vertical的。(例如:android:orientation=”vertical”)
- vertical的Guideline寬度為零,高度為ConstraintLayout的高度
- horizontal的Guideline高度為零,寬度為ConstraintLayout的高度
定位Guideline有三種方式:
- 指定距離左側或頂部的固定距離(layout_constraintGuide_begin)
- 指定距離右側或底部的固定距離(layout_constraintGuide_end)
- 指定在父控制元件中的寬度或高度的百分比(layout_constraintGuide_percent)
Guideline 的原始碼如下:
public class Guideline extends View {
public Guideline(Context context) {
super(context);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs) {
super(context, attrs);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
super.setVisibility(8);
}
public Guideline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr);
super.setVisibility(8);
}
public void setVisibility(int visibility) {
}
public void draw(Canvas canvas) {
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
this.setMeasuredDimension(0, 0);
}
}
複製程式碼
原始碼說明:
- 它預設是GONE的。8 就是View.GONE的值。
- 它的public void setVisibility(int visibility)方法被空實現了,所以使用者也沒辦法改變它的可見度。
- 推匯出它一定是GONE的。在螢幕上不可見
- this.setMeasuredDimension(0, 0); 和public void draw(Canvas canvas)的空實現,表明這是一個超輕量的View,不可見,沒有寬高,也不繪製任何東西。僅僅作為我們的錨點使用。
##總結
ConstraintLayout佈局剛開始學習的時候確實非常麻煩,但是所有的新鮮事物都是入手難,光理論肯定是不行的,總之自己動手豐衣足食。我自己也做個了demo傳送門,可以方便參考,謝謝大家提供意見!