天天看點

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

ConstraintLayout控件使用全攻略

标簽(空格分隔): Android

文章目錄

  • ConstraintLayout控件使用全攻略
    • 介紹
    • 位置限制
      • **1.相對位置**
      • **2.強制限制**
      • **3.基線對齊**
      • **4.圓心定位**
      • **5.百分比限制**
      • **6.Chains(鍊)**
      • **7.指定控件寬高百分比大小**
      • **8.goneMargin(隐藏邊距)**
      • **9.指定寬高比**
    • 輔助類
      • Group群組
      • Guideline
      • Barrier屏障
    • 參考

介紹

ConstraintLayout是Google的一個拖拽布局ViewGroup,釋出已經由來已久了,甚至建立Activity的頁面布局預設就是ConstraintLayout,可見Google對它的推薦态度。總之一句話,用了它各種強大的限制功能,能大大減少布局潛逃,達到布局優化的效果。

在使用ConstraintLayout之前,先進行靈魂三問:ConstraintLayout是什麼?為什麼要使用ConstraintLayout,它有什麼好處?怎麼用?

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

是什麼?

限制布局ConstraintLayout 是一個ViewGroup,可以在Api9以上的Android系統使用它,它的出現主要是為了解決布局嵌套過多的問題,以靈活的方式定位和調整小部件。從 Android Studio 2.3 起,官方的模闆預設使用 ConstraintLayout。

為什麼用ConstraintLayout?

ConstraintLayout的初衷是減少布局嵌套,再複雜的布局也可能由一個ConstraintLayout搞定,再加上近幾年支援的屬性越來越豐富,而且也是Google極力推薦的,ConstraintLayout在今後的開發和優化中一定會越來越不可或缺。甚至可以在一定程度上适配更多的螢幕尺寸。

怎麼用?

↓↓↓

本篇所舉例子和屬性都是基于2.0.0的beta版,引入方式:

dependencies{
    	implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
    }

           

位置限制

1.相對位置

相對位置是ConstraintLayout最基本的屬性,類似于RelativeLayout的相對布局,控制子控件的相對位置。

說起來比較抽象,舉個例子:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

像這樣的布局需要在代碼中這樣寫:

<Button
		android:id="@+id/btn_1"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="A"
		app:layout_constraintLeft_toLeftOf="parent"
		app:layout_constraintTop_toTopOf="parent" />
	
	<Button
		android:id="@+id/btn_2"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="B"
		app:layout_constraintLeft_toLeftOf="parent"
		app:layout_constraintTop_toBottomOf="@+id/btn_1" />
	
	<Button
		android:id="@+id/btn_3"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="C"
		app:layout_constraintLeft_toRightOf="@+id/btn_1"
		app:layout_constraintTop_toTopOf="parent" />

           

可見位置的控制主要是

app:layout_constraintTop_toBottomOf="@+id/btn_1"

屬性實作的,比如這句屬性表示:該View的頂部對齊至目标View的底部。

該系列屬性大概有12個,分别控制View的top,bottom,left,right,start,end

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

app:layout_constraintTop_toTopOf="@+id/xxx"

app:layout_constraintTop_toBottomOf="@+id/xxx"

app:layout_constraintBottom_toBottomOf="@+id/xxx"

app:layout_constraintBottom_toTopOf="@+id/xxx"

app:layout_constraintLeft_toLeftOf="@+id/xxx"

app:layout_constraintLeft_toRightOf="@+id/xxx"

app:layout_constraintStart_toStartOf="@+id/xxx"

app:layout_constraintStart_toEndOf="@+id/xxx"

app:layout_constraintRight_toRightOf="@+id/xxx"

app:layout_constraintRight_toLeftOf="@+id/xxx"

app:layout_constraintEnd_toEndOf="@+id/xxx"

app:layout_constraintEnd_toStartOf="@+id/xxx"

其中parent代表父控件,比如讓View居中可以這樣寫:

app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"

           

2.強制限制

如果要實作一個這樣的布局:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

使用ConstraintLayout實作起來代碼是這樣的:

<Button
		......
	    android:id="@+id/btn_a"
	    app:layout_constraintStart_toStartOf="parent"
	    app:layout_constraintTop_toTopOf="parent" />
    
    <Button
	    android:id="@+id/btn_b"
	    ......
	    app:layout_constraintEnd_toEndOf="parent"
	    app:layout_constraintStart_toEndOf="@+id/btn_a"
	    app:layout_constraintTop_toBottomOf="@+id/btn_a" />

           

本來可以開心的摸魚了,但有一天A控件的長度變的突然很長,于是出現了下面這樣的情況

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略
ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

B控件并沒有絕對在A的右邊,而且都超出螢幕了,這樣下去肯定不行,于是就要用到強制限制來拯救:

app:layout_constrainedWidth=“true”

這時隻要将上句代碼加入到B控件的xml配置中即可解決,效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

縱向的緯度對應:

app:layout_constrainedHeight=“true”

3.基線對齊

如果子View是TextView還可以使用基線對齊:

layout_constraintBaseline_toBaselineOf="@+id/xxx"

來寫個例子看下對齊效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

如果TextView的和大小高度可能不同:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略
ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

可以看到如果是多行的文字,這個屬性隻以文字第一行為基線進行對齊。

使用這個屬性還是需要注意一下的。

4.圓心定位

圓心定位用一張盜來的圖就可以表達的很清楚:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略
ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

由圖可見,圓心定位至少有三個屬性來确定限制關系

  1. app:layout_constraintCircle="@+id/btn_aa" 被限制控件Id
  1. app:layout_constraintCircleAngle=“0” 圓心偏移角度,豎直正方向方向為0度。
  1. app:layout_constraintCircleRadius=“68dp” 圓半徑。

由這三個屬性就可以共同使用來進行圓心的限制啦。

下面寫個例子來試試:

<--首選确定一個圓心View-->
	<Button
    	android:id="@+id/btn_aa"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="88dp"
        android:layout_marginEnd="8dp"
        android:text="圓心"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
		app:layout_constraintBottom_toBottomOf="parent />

	<--限制在圓心0度位置,也就是正上方-->
 	<View
        android:id="@+id/btn_bb"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@color/colorPrimary"
        app:layout_constraintCircle="@+id/btn_aa"
        app:layout_constraintCircleAngle="0"
        app:layout_constraintCircleRadius="68dp" />

	<--限制在圓心45度位置,也就是右上方-->
    <View
        android:id="@+id/btn_cc"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@color/colorPrimary"
        app:layout_constraintCircle="@+id/btn_aa"
        app:layout_constraintCircleAngle="45"
        app:layout_constraintCircleRadius="68dp" />

           

來看下效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

我又在以上代碼上多添加了幾個限制,實作了一個鐘表效果,其中綠色方塊中寫的是限制角度。

5.百分比限制

百分比限制的屬性有垂直百分比和水準百分比,分别是:

app:layout_constraintHorizontal_bias=“0.3”
app:layout_constraintVertical_bias=“0.3”

水準的百分比限制屬性意思是在确定了View的左側限制點和右側限制點之後,此時這個View相對于左右限制點的位置時居中的,也就是app:layout_constraintHorizontal_bias=“0.5”,如圖:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

我将View設定為相對于父布局的水準居中位置,也就是

app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
           

此時切換到Design視圖,點選該View,然後再右側可以看到

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

這樣的顯示,其中紅色箭頭所辨別的50就代表預設的百分比限制位置。此時可以直接拖動這個浮标來修改水準百分比限制,也可以在代碼中添加**app:layout_constraintHorizontal_bias=“0.3”**屬性來修改(直接拖動浮标會生成這句代碼)。

這就是水準百分比限制的作用,同理,豎直方向上的百分比限制也一樣。

寫個例子試試:

<Button
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="youlookwhat"
		app:layout_constraintBottom_toBottomOf="parent"
		app:layout_constraintEnd_toEndOf="parent"
		app:layout_constraintHorizontal_bias="0.2"
		app:layout_constraintStart_toStartOf="parent"
		app:layout_constraintTop_toTopOf="parent"
		app:layout_constraintVertical_bias="0.25" />

           

此按鈕在相對于父布局水準方向20%,相對于父布局豎直方向25%的位置。

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

6.Chains(鍊)

一組控件通過雙向限制關聯起來就形成了鍊。如圖:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

鍊的兩端一定是限制于parent的,鍊的風格由一條鍊的第一個控件決定:

app:layout_constraintHorizontal_chainStyle=“spread”

layout_constraintHorizontal_chainStyle

有三個枚舉值:

  • spread:均勻配置設定鍊所在緯度的所有空間 (預設)
  • spread_inside:将第一個元素和最後一個元素放置在邊緣上,并均勻分布其餘元素
  • packed:将鍊中元素居中在鍊條的中心

一張圖來說明:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略
  • 注意:一條鍊的屬性是由這條鍊的頭結點控制的。

同時鍊還支援權重,如果将width設定為0dp,并且增加layout_constraintHorizontal_weight屬性來設定權重,就可以建立出一條橫向的權重鍊了。

app:layout_constraintHorizontal_weight=“2” :水準方向上控件所占權重
app:layout_constraintVertical_weight=“1” :豎直方向上控件所占權重

舉個例子,來建立一個水準方向權重為1,2,1的鍊:

<Button
        android:id="@+id/btn_1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="窩窩頭"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/btn_2"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="一塊錢四個"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintLeft_toRightOf="@+id/btn_1"
        app:layout_constraintRight_toLeftOf="@+id/btn_3"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="嘿嘿"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintLeft_toRightOf="@+id/btn_2"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

           

效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

7.指定控件寬高百分比大小

ConstantLayout還可以指定子View的百分比尺寸(太強大了吧)。

一起來見證一下這個屬性:

app:layout_constraintHeight_percent=“0.5” :高相對于父布局的百分比,取值0~1
app:layout_constraintWidth_percent=“0.5” :寬相對于父布局的百分比

舉個例子,将下面的ImageView寬度設為父布局的一半,高度也是父布局的一半:

<ImageView
	    android:id="@+id/iv_111"
	    android:layout_width="0dp"
	    android:layout_height="0dp"
	    android:scaleType="fitXY"
	    android:src="@mipmap/hentai"
	    app:layout_constraintBottom_toBottomOf="parent"
	    app:layout_constraintHeight_percent="0.5"
	    app:layout_constraintLeft_toLeftOf="parent"
	    app:layout_constraintRight_toRightOf="parent"
	    app:layout_constraintTop_toTopOf="parent"
	    app:layout_constraintWidth_percent="0.5" />

           

效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略
  • 注意:當寬/高設為父布局的百分比後,寬/高也要指定為0dp,否則不會生效。

8.goneMargin(隐藏邊距)

在子view的狀态為gone時,goneMargin設定的邊距開始生效。

layout_goneMarginStart

layout_goneMarginEnd

layout_goneMarginLeft

layout_goneMarginTop

layout_goneMarginRight

layout_goneMarginBottom

9.指定寬高比

ConstantsLayout還有一個非常有趣的屬性:

app:layout_constraintDimensionRatio=“w,16:9”

可以通過該屬性來指定子控件的期望寬高比。

舉個例子來看,将一個圖檔寬高比設定為16:9,xml布局:

<ImageView
    	android:id="@+id/iv_111"
    	android:layout_width="0dp"
    	android:layout_height="wrap_content"
    	android:scaleType="fitXY"
    	android:src="@mipmap/hentai"
    	app:layout_constraintBottom_toBottomOf="parent"
    	app:layout_constraintDimensionRatio="w,16:9"
    	app:layout_constraintLeft_toLeftOf="parent"
    	app:layout_constraintRight_toRightOf="parent"
    	app:layout_constraintTop_toTopOf="parent" />

           

來看下效果,左圖是圖檔原始效果,右圖是指定寬高後的亞子

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略
ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

說明一下,layout_constraintDimensionRatio比例字首預設為h,思是寬高比例,例如h,3:2意思為寬3:高2,而指定了屬性w,3:2,意思就成了高寬比,即高3:寬2。

再說明一下,經過我的測試發現若要成功實作期望寬高比,寬或高一方要有固定的值或wrap_content,另一個屬性則要設為0dp,否則該屬性不會生效。

輔助類

Group群組

ConstrantLayout提供了Group來标記多個控件的群組,群組可以指定多個控件,并通過控制Group來實作對這多個控件的操作。

Group群組是一個獨立的View控件,但不會真正顯示在螢幕上,該View最常用的屬性是constraint_referenced_ids,用來指定群組中包含的id。

app:constraint_referenced_ids=“btn_a_1,btn_a_2,btn_a_3” :指定群組包含的控件id。
<androidx.constraintlayout.widget.Group
    	android:id="@+id/group_a"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	app:constraint_referenced_ids="btn_a_1,btn_a_2,btn_a_3" />

           

舉個例子,點選讓一個Group群組的控件來顯示隐藏:

java代碼:

public void showHide(View view) {
    	groupA.setVisibility((groupA.getVisibility() == View.GONE) ? View.VISIBLE : View.GONE);
    }

           

xml代碼:

<Button
    	android:id="@+id/btn_a_1"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:text="A1"
    	app:layout_constraintLeft_toLeftOf="parent"
    	app:layout_constraintTop_toTopOf="parent" />
    
    <Button
    	android:id="@+id/btn_a_2"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:text="A2"
    	app:layout_constraintLeft_toLeftOf="parent"
    	app:layout_constraintTop_toBottomOf="@+id/btn_a_1" />
    
    <Button
    	android:id="@+id/btn_a_3"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:text="A3"
    	app:layout_constraintLeft_toLeftOf="parent"
    	app:layout_constraintTop_toBottomOf="@+id/btn_a_2" />
    
    <androidx.constraintlayout.widget.Group
    	android:id="@+id/group_a"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	app:constraint_referenced_ids="btn_a_1,btn_a_2,btn_a_3" />
    
    <Button
    	android:id="@+id/btn_sh"
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:onClick="showHide"
    	android:text="顯/隐"
    	app:layout_constraintLeft_toLeftOf="parent"
    	app:layout_constraintRight_toRightOf="parent"
    	app:layout_constraintTop_toTopOf="parent" />


           

看下效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

Guideline

輔助線Guideline會在預覽的時候幫助你完成布局,運作時并不會顯示在界面上。

Guideline最常用的兩個屬性是:

android:orientation=“horizontal” :輔助線方向,有兩個枚舉值:horizontal和vertical,顧名思義,代表水準和豎直方向。
app:layout_constraintGuide_percent=“0.5” :輔助線相對父布局百分比位置。

Guideline的使用很簡單,下面舉個例子,來個拍照時常用的黃金分隔輔助線:

<androidx.constraintlayout.widget.Guideline
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:orientation="horizontal"
    	app:layout_constraintGuide_percent="0.33" />
    
    <androidx.constraintlayout.widget.Guideline
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:orientation="horizontal"
    	app:layout_constraintGuide_percent="0.66" />
    
    <androidx.constraintlayout.widget.Guideline
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:orientation="vertical"
    	app:layout_constraintGuide_percent="0.33" />
    
    <androidx.constraintlayout.widget.Guideline
    	android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
    	android:orientation="vertical"
    	app:layout_constraintGuide_percent="0.66" />

           

效果:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

Barrier屏障

顧名思義就是對需要限制的View控件間施加一個水準或豎直的屏障,來實作一對多或多對多的限制關系。

文字太抽象,還是偷張圖來了解:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

如圖,這也是經常碰到的需求,一個View要同時再幾個View的右側,并且這幾個View的長度還是可變的,這時無論依賴哪個單獨View都不滿足需求。這時候就需要Barrier屏障來滿足需求了。

Barrier是一個單獨的View,它不會顯示在界面上,可以放心大膽的用。

Barrier的屬性有:

app:constraint_referenced_ids=“btn_1,btn_2” :列出屏障所包含的View的id,對應于圖中左側的三個View。
app:barrierDirection=“right” :Barrier所在View組的位置,有right,left,top和bottom枚舉值可選。
app:barrierMargin=“10dp” :Barrier屏障與控件間間距。
app:barrierAllowsGoneWidgets=“true” :如果Barrier屏障所包含View被設定為Gone,是否影響Barrier位置。如果你不想讓Barrier考慮GONE的view,可以通過将屬性barrierAllowsGoneWidgets設定 為false(預設為true)來更改此設定。

知道了這四個屬性,就可以得心應手的使用Barrier了,舉個例子:

<Button
        android:id="@+id/btn_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="grow"
        android:text="窩窩頭"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.35" />

    <Button
        android:id="@+id/btn_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="grow"
        android:text="一塊錢四個"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.65" />

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierAllowsGoneWidgets="true"
        app:barrierDirection="right"
        app:barrierMargin="10dp"
        app:constraint_referenced_ids="btn_1,btn_2" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="嘿嘿"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toRightOf="@+id/barrier_1"
        app:layout_constraintTop_toTopOf="parent" />

           

點選事件:

public void grow(View view) {
        String str = ((TextView) view).getText().toString();
        str += "~~~";
        ((TextView) view).setText(str);
    }

           

上面代碼表示為窩窩頭 和 一塊錢四個 兩個View建立右側屏障Barrier_1,嘿嘿限制在Barrier_1屏障的右側,被屏障包含的窩窩頭和一塊錢四個寬度發生變化時,限制還是關系不會改變。

效果圖:

ConstraintLayout控件使用淺析ConstraintLayout控件使用全攻略

一不小心就把嘿嘿頂到了視窗外,因為嘿嘿隻有錯側限制了Barrier屏障,并沒有為右側添加限制關系,是以才導緻這個bug,同時也要注意本篇文章所講的強制限制屬性。

軟體開發還是要細心,要有窮盡所有可能情況的習慣,避免低級bug。

參考

https://juejin.im/post/5bac92f2f265da0aba70c1bf#heading-1

https://juejin.im/post/5b013e6f51882542c760dc7b