Android開發約束佈局ConstraintLayout學習總結

小夥伴都知道Android開發有常用的五大布局:LinearLayout、RelateLayout、FrameLayout、AbsolutLayout和TableLayout,今天再總結一個比較牛掰的一個佈局——ConstraintLayout,完全可以代替LinearLayout和RelateLayout,具體爲什麼要使用他和怎麼用是接下來需要說的。

ConstraintLayout介紹

約束佈局ConstraintLayout是一個Support庫,可以在Api9以上的Android系統使用它,它的出現主要是爲了解決佈局嵌套過多的問題,以靈活的方式定位和調整小部件。從Android Studio 2.3起,官方的模板默認使用ConstraintLayout。

ConstraintLayout使用緣由

在開發過程中經常能遇到一些複雜的UI,可能會出現佈局嵌套過多的問題,嵌套得越多,設備繪製視圖所需的時間和計算功耗也就越多,遇到此情況我們更多的是採用RelativeLayout。

既然用RelativeLayout可以解決問題,爲什麼還要使用ConstraintLayout呢?因爲ConstraintLayout使用起來比RelativeLayout更靈活,性能更出色!還有一點就是ConstraintLayout可以按照比例約束控件位置和尺寸,能夠更好地適配屏幕大小不同的機型。

ConstraintLayout用法

添加依賴

首先我們需要在app/build.gradle文件中添加ConstraintLayout的依賴:

implementation 'com.android.support.constraint:constraint-layout:1.1.3'

相對定位

相對定位是部件對於另一個位置的約束,如圖:
相對定位示例

相應的代碼:

<TextView
    android:id="@+id/TextView1"
    ...
    android:text="TextView1" />

<TextView
    android:id="@+id/TextView2"
    ...
    app:layout_constraintLeft_toRightOf="@+id/TextView1" />

面代碼中在TextView2裏用到了app:layout_constraintLeft_toRightOf="@+id/TextView1"這個屬性,他的意思是把TextView2的左邊約束到TextView1的右邊

相對定位的常用屬性

  • layout_constraintLeft_toLeftOf
    view1左邊對齊view2的左邊
  • layout_constraintLeft_toRightOf
    view1左邊對齊view2的右邊
  • layout_constraintRight_toLeftOf
    view1右邊對齊view2的左邊
  • layout_constraintRight_toRightOf
    view1右邊對齊view2的右邊
  • layout_constraintTop_toTopOf
    view1頂部對齊view2的頂部
  • layout_constraintTop_toBottomOf
    view1頂部對齊view2的底部
  • layout_constraintBottom_toTopOf
    view1底部對齊view2的頂部
  • layout_constraintBottom_toBottomOf
    view1底部對齊view2的底部
  • layout_constraintBaseline_toBaselineOf
    view1基準線對齊view2的基準線
  • layout_constraintStart_toEndOf
    view1起始位置對齊view2的結束位置
  • layout_constraintStart_toStartOf
    view1起始位置view2的起始位置
  • layout_constraintEnd_toStartOf
    view1結束位置對齊view2的起始位置
  • layout_constraintEnd_toEndOf
    view1結束位置對齊view2的結束位置

兩個TextView的高度不一致,但是又希望他們文本對齊,這個時候就可以使用layout_constraintBaseline_toBaselineOf,代碼如下:

<TextView
    android:id="@+id/TextView1"
    .../>

<TextView
    android:id="@+id/TextView2"
    ...
    app:layout_constraintLeft_toRightOf="@+id/TextView1" 
    app:layout_constraintBaseline_toBaselineOf="@+id/TextView1"/>

效果如下:
layout_constraintBaseline_toBaselineOf效果圖

角度定位

角度定位指的是可以用一個角度和一個距離來約束兩個空間的中心。舉例:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintCircle="@+id/TextView1"
    app:layout_constraintCircleAngle="120"
    app:layout_constraintCircleRadius="150dp" />

上面例子中的TextView2用到了3個屬性:
app:layout_constraintCircle="@+id/TextView1"
app:layout_constraintCircleAngle=“120”(角度)
app:layout_constraintCircleRadius=“150dp”(距離)

指的是TextView2的中心在TextView1的中心的120度,距離爲150dp,效果如下:
角度定位效果圖

邊距

常用margin

  • android:layout_marginStart
  • android:layout_marginEnd
  • android:layout_marginLeft
  • android:layout_marginTop
  • android:layout_marginRight
  • android:layout_marginBottom

在使用margin的時候要注意兩點:

  1. 在ConstraintLayout裏面要實現margin,必須先約束該控件在ConstraintLayout裏的位置
  2. margin只能大於等於0

goneMargin

goneMargin主要用於約束的控件可見性被設置爲gone的時候使用的margin值,屬性如下:

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

假設TextView2的左邊約束在TextView1的右邊,並給TextView2設一個app:layout_goneMarginLeft=“10dp”,代碼如下:

<android.support.constraint.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/TextView1"
        .../>

    <TextView
        android:id="@+id/TextView2"
        ...
        app:layout_constraintLeft_toRightOf="@+id/TextView1"
        app:layout_goneMarginLeft="10dp"
        />

</android.support.constraint.ConstraintLayout>

效果圖:
goneMargin效果圖1

這個時候把TextView1的可見性設爲gone,效果如下:
goneMargin效果圖2

extView1消失後,TextView2有一個距離左邊10dp的邊距。

居中

ConstraintLayout居中寫法:

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

水平居中:

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

垂直居中:

app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"

偏移

居中後可採用margin進行適當偏移:

<TextView
    android:id="@+id/TextView1"
    ...
    android:layout_marginLeft="100dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent" />

居中後margin適當偏移效果圖

除了這種偏移外,ConstraintLayout還提供了另外一種偏移的屬性:

  • layout_constraintHorizontal_bias 水平偏移
  • layout_constraintVertical_bias 垂直偏移

例子:

<TextView
    android:id="@+id/TextView1"
    ...
    app:layout_constraintHorizontal_bias="0.3"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent" />

layout_constraintHorizontal_bias偏移效果圖

解釋:
居中時layout_constraintHorizontal_bias默認爲0.5即50%(左偏移50%右偏移50%),0.3(左偏移30%右偏移70%)

尺寸約束

控件的尺寸可以通過四種不同方式指定。

使用指定的尺寸

這個就不說了。

使用wrap_content

當控件的高度或寬度爲wrap_content時,可以使用下列屬性來控制最大、最小的高度或寬度:

  • android:minWidth 最小的寬度
  • android:minHeight 最小的高度
  • android:maxWidth 最大的寬度
  • android:maxHeight 最大的高度

另外使用這些屬性需要加上強制約束:

  • app:constrainedWidth=”true”
  • app:constrainedHeight=”true”

使用0dp

官方不推薦在ConstraintLayout中使用match_parent,可以設置 0dp (MATCH_CONSTRAINT) 配合約束代替match_parent,例如:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginLeft="50dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    android:visibility="visible" />

寬度設爲0dp,左右兩邊約束parent的左右兩邊,並設置左邊邊距爲50dp,效果如下:
0dp代替MATCH_CONSTRAINT效果圖

控件內寬高比

當寬或高至少有一個尺寸被設置爲0dp時,可以通過屬性layout_constraintDimensionRatio設置寬高比,舉個例子:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintDimensionRatio="1:1"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent" />

寬設置爲0dp,寬高比設置爲1:1,這個時候TextView1是一個正方形。

除此之外,在設置寬高比的值的時候,還可以在前面加W或H,分別指定寬度或高度限制。 例如:

app:layout_constraintDimensionRatio="H,2:3"指的是 高:=2:3
app:layout_constraintDimensionRatio="W,2:3"指的是 寬:=2:3

如果兩個或以上控件通過下圖的方式約束在一起,就可以認爲是他們是一條鏈。

例如:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/TextView2" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toLeftOf="@+id/TextView3"
    app:layout_constraintRight_toRightOf="parent" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView2"
    app:layout_constraintRight_toRightOf="parent" />

個TextView相互約束,兩端兩個TextView分別與parent約束,成爲一條鏈,效果如下:
鏈效果圖

鏈樣式

一條鏈的第一個控件是這條鏈的鏈頭,我們可以在鏈頭中設置 layout_constraintHorizontal_chainStyle來改變整條鏈的樣式,提供有三種樣式:

  • spread
  • spread_inside
  • packed

對應這三種樣式的效果圖如下:
鏈三種樣式效果圖

權重鏈

可以留意到上面所用到的3個TextView寬度都爲wrap_content,如果我們把寬度都設爲0dp,這個時候可以在每個TextView中設置橫向權重layout_constraintHorizontal_weight(constraintVertical爲縱向)來創建一個權重鏈,如下所示:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/TextView2"
    app:layout_constraintHorizontal_weight="2" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView1"
    app:layout_constraintRight_toLeftOf="@+id/TextView3"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_weight="3" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView2"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintHorizontal_weight="4" />

效果圖如下:
權重鏈效果圖

輔助工具

Optimizer(約束優化)

當我們使用 MATCH_CONSTRAINT 時,ConstraintLayout 將對控件進行 2 次測量,ConstraintLayout在1.1中可以通過設置 layout_optimizationLevel 進行優化,可設置的值有:

  • none:無優化
  • standard:僅優化直接約束和屏障約束(默認)
  • direct:優化直接約束
  • barrier:優化屏障約束
  • chain:優化鏈約束
  • dimensions:優化尺寸測量

Barrier(屏障標準)

假設有3個控件ABC,C在AB的右邊,但是AB的寬是不固定的,這個時候C無論約束在A的右邊或者B的右邊都不對。當出現這種情況可以用Barrier來解決。Barrier可以在多個控件的一側建立一個屏障,如下所示:
Barrier屏障標準示意圖

這個時候C只要約束在Barrier的右邊就可以了,代碼如下:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintTop_toBottomOf="@+id/TextView1" />

<android.support.constraint.Barrier
    android:id="@+id/barrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="right"
    app:constraint_referenced_ids="TextView1,TextView2" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/barrier" />

其中:

  • app:barrierDirection爲屏障所在的位置,可設置的值有:bottom、end、left、right、start、top
  • app:constraint_referenced_ids爲屏障引用的控件,可設置多個(用“,”隔開)

Group(組概念)

Group可以把多個控件歸爲一組,方便隱藏或顯示一組控件:

<TextView
    android:id="@+id/TextView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/TextView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@+id/TextView1" />

<TextView
    android:id="@+id/TextView3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toRightOf="@id/TextView2" />

組概念效果圖
現在有3個並排的TextView,用Group把TextView1和TextView3歸爲一組,再設置這組控件的可見性,如下所示:
組隱藏效果圖

Placeholder(佔位符)

Placeholder指的是佔位符。在Placeholder中可使用setContent()設置另一個控件的id,使這個控件移動到佔位符的位置:

<android.support.constraint.Placeholder
    android:id="@+id/placeholder"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:content="@+id/textview"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<TextView
    android:id="@+id/textview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#cccccc"
    android:padding="16dp"
    android:text="TextView"
    android:textColor="#000000"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

新建一個Placeholder約束在屏幕的左上角,新建一個TextView約束在屏幕的右上角,在Placeholder中設置 app:content="@+id/textview",這時TextView會跑到屏幕的左上角。效果如下:
佔位符效果圖

Guideline(輔助線)

Guildline像輔助線一樣,在預覽的時候幫助你完成佈局(不會顯示在界面上)。

Guildline的主要屬性:

  • android:orientation 垂直vertical,水平horizontal
  • layout_constraintGuide_begin 開始位置
  • layout_constraintGuide_end 結束位置
  • layout_constraintGuide_percent 距離頂部的百分比(orientation = horizontal時則爲距離左邊)

例如:

<android.support.constraint.Guideline
    android:id="@+id/guideline1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_begin="50dp" />

<android.support.constraint.Guideline
    android:id="@+id/guideline2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />

guideline1爲水平輔助線,開始位置是距離頂部50dp,guideline2位垂直輔助線,開始位置爲屏幕寬的0.5(中點位置),效果如下:
guideline效果圖

參考

  • https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout
  • https://www.jianshu.com/p/17ec9bd6ca8a
  • https://blog.csdn.net/qq_38520096/article/details/80813994
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章