Android開發筆記(一百四十九)約束佈局ConstraintLayout
阿新 • • 發佈:2019-02-08
約束佈局ConstraintLayout是Android Studio 2.2推出的新佈局,並從Android Studio 2.3開始成為預設佈局檔案的根佈局,由此可見Android官方對其寄予厚望,那麼約束佈局究竟具備哪些激動人心的特性呢?
傳統的佈局如線性佈局LinearLayout、相對佈局RelativeLayout等等,若要描繪不規則的複雜介面,往往需要進行多重的佈局巢狀,不但僵硬死板缺乏靈活性,並且巢狀過多拖慢頁面渲染速度。約束佈局正是為了解決這些問題應運而生,它兼顧靈活性和高效率,可以看作是相對佈局的升級版,在很大程度上改善了Android的使用者體驗。開發者使用約束佈局之時,有多種手段往該佈局內新增和拖動控制元件,既能像原型設計軟體AxureRP那樣在畫板上任意拖曳控制元件,也能像傳統佈局那樣在XML檔案中調整控制元件佈局,還能在程式碼中動態修改控制元件物件的位置狀態,下面分別介紹約束佈局的這幾種使用方式:
設計師通過工具軟體三兩下就勾勒出介面原型,程式設計師卻得一個控制元件一個控制元件地小心佈局,並對控制元件位置不斷微調以符合原型上的尺寸比例。Android原先的介面手工編碼一直為人所詬病,因為“所見即所得”才是介面編碼的理想方式,比如iOS很早就在Xcode中集成了故事板,使得iOS程式設計師能夠像設計師那樣在畫板上拖動控制元件,從而加快了介面編碼的工作效率。自從ConstraintLayout誕生之後,Android程式設計師終於跟上時代步伐,也能在約束佈局內部隨意拖曳控制元件,同時存在主從關係的控制元件之間,附庸控制元件會跟隨目標控制元件一起移動,從而省卻了介面微調的大量勞動。
畫板上的控制元件拖動操作,三言兩語說不清楚,還是觀看具體的動圖比較一目瞭然:
layout_constraintTop_toTopOf : 該控制元件的頂部與另一個控制元件的頂部對齊
layout_constraintTop_toBottompOf : 該控制元件的頂部與另一個控制元件的底部對齊
layout_constraintBottom_toTopOf : 該控制元件的底部與另一個控制元件的頂部對齊
layout_constraintBottom_toBottomOf : 該控制元件的底部與另一個控制元件的底部對齊
layout_constraintLeft_toLeftOf : 該控制元件的左側與另一個控制元件的左側對齊
layout_constraintLeft_toRightOf : 該控制元件的左側與另一個控制元件的右側對齊
layout_constraintRight_toLeftOf : 該控制元件的右側與另一個控制元件的左側對齊
layout_constraintRight_toRightOf : 該控制元件的右側與另一個控制元件的右側對齊
下面是一個運用約束佈局的XML檔案例子:
topToTop : 當前控制元件的頂部與指定ID的控制元件頂部對齊
topToBottom : 當前控制元件的頂部與指定ID的控制元件底部對齊
bottomToTop : 當前控制元件的底部與指定ID的控制元件頂部對齊
bottomToBottom : 當前控制元件的底部與指定ID的控制元件底部對齊
startToStart : 當前控制元件的左側與指定ID的控制元件左側對齊
startToEnd : 當前控制元件的左側與指定ID的控制元件右側對齊
endToStart : 當前控制元件的右側與指定ID的控制元件左側對齊
endToEnd : 當前控制元件的右側與指定ID的控制元件右側對齊
下面是在約束佈局中新增新控制元件的程式碼例子:
可是按照傳統的佈局引數方式存在諸多不便之處,比如以下幾點就很不合理:
1、控制元件約束關係的指定,與間距設定是分開的,其他人難以找到二者之間的對應關係;
2、setMargins方法同時設定上下左右四個方向的間距,無法單獨設定某個方向的間距;
3、佈局引數在啟用時立即生效,沒有漸變的過程,讓使用者覺得很突兀。從下面的動圖就看到這個位置一下子發生變化,使用者體驗很不好:
為了改進以上幾個問題,constraint-layout開發包從1.0.1本版開始,增加了新的約束設定類ConstraintSet,該工具針對這幾個問題分別給出了相應的解決方案:
1、提供connect方法,一次性指定存在約束關係的兩個控制元件,以及它們的間距;
2、提供setMargin方法,允許單獨設定上下左右某個方向的間距;
3、提供了漸變管理類TransitionManager,支援展示空間位置變化的切換動畫;
下面是使用ConstraintSet修改控制元件位置的具體程式碼:
點此檢視Android開發筆記的完整目錄
__________________________________________________________________________
本文現已同步釋出到微信公眾號“老歐說安卓”,開啟微信掃一掃下面的二維碼,或者直接搜尋公眾號“老歐說安卓”新增關注,更快更方便地閱讀技術乾貨。
傳統的佈局如線性佈局LinearLayout、相對佈局RelativeLayout等等,若要描繪不規則的複雜介面,往往需要進行多重的佈局巢狀,不但僵硬死板缺乏靈活性,並且巢狀過多拖慢頁面渲染速度。約束佈局正是為了解決這些問題應運而生,它兼顧靈活性和高效率,可以看作是相對佈局的升級版,在很大程度上改善了Android的使用者體驗。開發者使用約束佈局之時,有多種手段往該佈局內新增和拖動控制元件,既能像原型設計軟體AxureRP那樣在畫板上任意拖曳控制元件,也能像傳統佈局那樣在XML檔案中調整控制元件佈局,還能在程式碼中動態修改控制元件物件的位置狀態,下面分別介紹約束佈局的這幾種使用方式:
在畫板上拖曳控制元件
畫板上的控制元件拖動操作,三言兩語說不清楚,還是觀看具體的動圖比較一目瞭然:
在XML檔案中調整控制元件佈局
傳統佈局如線性佈局、相對佈局基本是在XML檔案中手工新增控制元件節點,約束佈局當然也允許在佈局檔案中指定控制元件的相對位置,這跟相對佈局內部的控制元件位置調整類似,只不過用來表示位置的屬性換了個名字罷了。與控制方位有關的屬性說明如下所示:layout_constraintTop_toTopOf : 該控制元件的頂部與另一個控制元件的頂部對齊
layout_constraintTop_toBottompOf : 該控制元件的頂部與另一個控制元件的底部對齊
layout_constraintBottom_toTopOf : 該控制元件的底部與另一個控制元件的頂部對齊
layout_constraintBottom_toBottomOf : 該控制元件的底部與另一個控制元件的底部對齊
layout_constraintLeft_toLeftOf : 該控制元件的左側與另一個控制元件的左側對齊
layout_constraintLeft_toRightOf : 該控制元件的左側與另一個控制元件的右側對齊
layout_constraintRight_toLeftOf : 該控制元件的右側與另一個控制元件的左側對齊
layout_constraintRight_toRightOf : 該控制元件的右側與另一個控制元件的右側對齊
下面是一個運用約束佈局的XML檔案例子:
與該佈局檔案對應的效果介面如下圖所示:<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/cl_content" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_first" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="40dp" app:layout_constraintLeft_toLeftOf="parent" android:layout_marginLeft="200dp" android:background="@color/blue" android:text="我是山大王" android:textSize="17sp" android:textColor="@color/black" /> <TextView android:id="@+id/tv_second" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="40dp" app:layout_constraintTop_toBottomOf="@+id/tv_first" android:layout_marginLeft="20dp" app:layout_constraintLeft_toLeftOf="@+id/tv_first" android:background="@color/blue" android:text="我是巡山的小嘍囉" android:textSize="17sp" android:textColor="@color/black" /> </android.support.constraint.ConstraintLayout>
在程式碼中新增控制元件
若要利用程式碼給約束佈局動態新增控制元件,則可照常呼叫addView方法,不同之處在於,新控制元件的佈局引數必須使用約束佈局的佈局引數,即ConstraintLayout.LayoutParams,該引數通過setMargins/setMarginStart/setMarginEnd方法設定新控制元件與周圍控制元件的間距,至於新控制元件與周圍控制元件的位置約束關係,則可參照ConstraintLayout.LayoutParams的下列屬性說明:topToTop : 當前控制元件的頂部與指定ID的控制元件頂部對齊
topToBottom : 當前控制元件的頂部與指定ID的控制元件底部對齊
bottomToTop : 當前控制元件的底部與指定ID的控制元件頂部對齊
bottomToBottom : 當前控制元件的底部與指定ID的控制元件底部對齊
startToStart : 當前控制元件的左側與指定ID的控制元件左側對齊
startToEnd : 當前控制元件的左側與指定ID的控制元件右側對齊
endToStart : 當前控制元件的右側與指定ID的控制元件左側對齊
endToEnd : 當前控制元件的右側與指定ID的控制元件右側對齊
下面是在約束佈局中新增新控制元件的程式碼例子:
private void addNewView() {
TextView tv = new TextView(this);
tv.setText("長按刪除該文字");
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17);
tv.setGravity(Gravity.CENTER);
tv.setBackgroundColor(Color.YELLOW);
ConstraintLayout.LayoutParams container = new ConstraintLayout.LayoutParams(
ConstraintLayout.LayoutParams.WRAP_CONTENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT
);
//設定控制元件左側與另一個控制元件的左側對齊
//水平方向上只能使用start和end,因為left和right可能無法奏效
container.startToStart = mLastViewId;
//設定控制元件頂部與另一個控制元件的底部對齊
container.topToBottom = mLastViewId;
container.setMargins(0, Utils.dip2px(this, 30), 0, 0);
//左側間距要使用Start,不能用Left,因為set.applyTo方法會清空Left的間距
container.setMarginStart(Utils.dip2px(this, 10));
tv.setLayoutParams(container);
tv.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View vv) {
cl_content.removeView(vv);
return true;
}
});
mLastViewId += 1000;
tv.setId(mLastViewId);
cl_content.addView(tv);
}
新增新控制元件的效果動圖如下所示:在程式碼中動態調整控制元件位置
有時根據使用者在介面上的操作,需要立即調整相關控制元件的顯示位置,這要在程式碼中修改控制元件的位置引數。既然新增控制元件時可以通過佈局引數指定控制元件位置,那麼調整控制元件位置一樣也可以通過佈局引數來實現,基本流程依次為:先呼叫getLayoutParams方法獲得當前的佈局引數->再指定新的控制元件約束關係及間距->最後呼叫setLayoutParams啟用新的佈局引數。可是按照傳統的佈局引數方式存在諸多不便之處,比如以下幾點就很不合理:
1、控制元件約束關係的指定,與間距設定是分開的,其他人難以找到二者之間的對應關係;
2、setMargins方法同時設定上下左右四個方向的間距,無法單獨設定某個方向的間距;
3、佈局引數在啟用時立即生效,沒有漸變的過程,讓使用者覺得很突兀。從下面的動圖就看到這個位置一下子發生變化,使用者體驗很不好:
為了改進以上幾個問題,constraint-layout開發包從1.0.1本版開始,增加了新的約束設定類ConstraintSet,該工具針對這幾個問題分別給出了相應的解決方案:
1、提供connect方法,一次性指定存在約束關係的兩個控制元件,以及它們的間距;
2、提供setMargin方法,允許單獨設定上下左右某個方向的間距;
3、提供了漸變管理類TransitionManager,支援展示空間位置變化的切換動畫;
下面是使用ConstraintSet修改控制元件位置的具體程式碼:
private void moveView() {
//使用動畫展示新舊約束關係的切換過程。如果刪掉這行則不展示切換動畫
TransitionManager.beginDelayedTransition(cl_content);
int margin = Utils.dip2px(this, isMoved?200:20);
//需要下載最新的constraint-layout,才能使用ConstraintSet
ConstraintSet set = new ConstraintSet();
//複製原有的約束關係
set.clone(cl_content);
//清空該控制元件的約束關係
//set.clear(tv_first.getId());
//設定該控制元件的約束寬度
//set.constrainWidth(tv_first.getId(), ConstraintLayout.LayoutParams.WRAP_CONTENT);
//設定該控制元件的約束高度
//set.constrainHeight(tv_first.getId(),ConstraintLayout.LayoutParams.WRAP_CONTENT);
//設定該控制元件的頂部約束關係與間距
//set.connect(tv_first.getId(), ConstraintSet.TOP, cl_content.getId(), ConstraintSet.BOTTOM, margin);
//設定該控制元件的底部約束關係與間距
//set.connect(tv_first.getId(), ConstraintSet.BOTTOM, cl_content.getId(), ConstraintSet.BOTTOM, margin);
//設定該控制元件的左側約束關係與間距
set.connect(tv_first.getId(), ConstraintSet.START, cl_content.getId(), ConstraintSet.START, margin);
//設定該控制元件的右側約束關係與間距
//set.connect(tv_first.getId(), ConstraintSet.END, cl_content.getId(), ConstraintSet.END, margin);
//LEFT和RIGHT的margin不管用,只有START和END的margin才管用
//set.setMargin(tv_init.getId(), ConstraintSet.START, 200);
//啟用新的約束關係
set.applyTo(cl_content);
isMoved = !isMoved;
}
上述變更控制元件位置程式碼的對應效果圖如下所示,有了切換動畫這下看起來比較柔和了:點此檢視Android開發筆記的完整目錄
__________________________________________________________________________
本文現已同步釋出到微信公眾號“老歐說安卓”,開啟微信掃一掃下面的二維碼,或者直接搜尋公眾號“老歐說安卓”新增關注,更快更方便地閱讀技術乾貨。