ConstraintLayout完全解析

一、概述

ConstraintLayout(約束布局),是Google在2016年推出的一種布局,其簡單、扁平化的使用方式,深得廣大開發者的喜愛。這篇文章我們不探討其性能方面的優勢。意在于和大家一起學習ConstraintLayout的相關使用。

implementation 'com.android.support.constraint:constraint-layout:1.1.2'
二、可視化界面的使用

Android Studio 2.2開始提供了對ConstraintLayout可視化的操作。對于可視化操作方面內容。這里大家可以通過郭霖大神的博客進行學習。

三、屬性介紹

屬性介紹是我們ConstraintLayout重點要學習的部分。可視化界面只是簡化了我們使用,對它所使用的屬性,我們要至少知道其意,并可以進行簡單的修改和手寫布局。
1、相對位置屬性

  • layout_constraintLeft_toLeftOf :當前View的左側和另一個View的左側位置對齊
  • layout_constraintLeft_toRightOf :當前view的左側會在另一個View的右側位置
  • layout_constraintRight_toLeftOf :當前view的右側會在另一個View的左側位置
  • layout_constraintRight_toRightOf :當前View的右側和另一個View的右側位置對齊
  • layout_constraintTop_toTopOf :頭部對齊
  • layout_constraintTop_toBottomOf :當前View在另一個View的下側
  • layout_constraintBottom_toTopOf :當前View在另一個View的上方
  • layout_constraintBottom_toBottomOf :底部對齊
  • layout_constraintBaseline_toBaselineOf :文字底部對齊
  • layout_constraintStart_toEndOf :同left_toRightOf
  • layout_constraintStart_toStartOf :同left_toLeftOf
  • layout_constraintEnd_toStartOf :同right_toLeftOf
  • layout_constraintEnd_toEndOf :同right_toRightOf

從ConstraintLayout的相對位置屬性可以看出和我們的RelativeLayout很相似,這也是有人將ConstraintLayout成為增強型的相對布局的原因,不過,其實現思想是完全不同的。從下面的例子我們可以看出來。

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btA"
        android:layout_width="148dp"
        android:layout_height="wrap_content"
        android:text="ButtonA"
        />
    <Button
        android:id="@+id/btB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ButtonB"
        android:layout_toRightOf="@id/btA"
        android:layout_alignParentRight="true"
        />
</RelativeLayout>
1-1

在圖片1-1中,我們使用RelativeLayout布局實現ButtonB在ButtonA的右側并填滿右側空間,我們將ButtonB的width設置為wrap_content,并且使用 android:layout_toRightOf="@id/btA"和android:layout_alignParentRight="true"兩個相對屬性。現在我們將布局改為ConstraintLayout并將相對屬性改為app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_to
EndOf="@+id/buttonB"

<android.support.constraint.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">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="buttonB"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/buttonA" />

    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="buttonA"
        />
</android.support.constraint.ConstraintLayout>
1-2

我們通過對比可以發現ButtonB同樣是wrap_content,但是我們的RelativeLayout會改變我們的View大小。而ConstraintLayout并不會,他會像橡皮筋一樣拉著我們的View使他在我們的右側居中。并不會改變view的大小。當我們的View寬度足夠大的時候超過了我們又側剩余寬度。也只是如1-3一樣,左右兩側的約束一樣大,使之感覺還是居中的。寬度還是我們設置的寬度并未被改變


1-3

接下來,如果我們想要讓我們的ConstraintLayout實現的效果和RelativeLayout一樣。官方給我們提供了一個match_constrain也就是0dp,我們為ButtonB的寬度設置為match_constrain(0dp)就可以將我們的ButtonB填滿我們右側的布局了。而官方對match_constrain的解釋為

  • Important: MATCH PARENT is not supported for widgets contained in a ConstraintLayout, though similar behavior can be defined by using MATCH CONSTRAINT with the corresponding left/right or top/bottom constraints being set to “parent”.

可以理解為在ConstraintLayout中已經不支持MATCH_PARENT,你可以通過MATCH_CONSTRAINT配合約束實現類似的效果。

理解了上面的內容我們來看一下類似的內容:強制約束。當我們的ButtonB的width設置為wrap_content的時候,而我們的ButtonB的內容過長就會像下圖一樣。導致約束失效。


1-4

而為了防止約束失效,在1.1.0版本中新增了一下屬性。

  • app:layout_constrainedWidth=”true|false” //默認false
  • app:layout_constrainedHeight=”true|false” //默認false
<?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:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="buttonA"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="buttonbuttonbuttonbuttonbuttonbuttonbutton"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/buttonA"
        app:layout_constrainedWidth="true"
    />

</android.support.constraint.ConstraintLayout>
1-5

2、GoneMargin

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom
    我們對Margin這個屬性應該很熟悉,GoneMargin也很簡單,他的含義就是當一個控件和另一個控件綁定后,如果另一個控件設置為Gone則,GoneMargin這組屬性會生效。
<?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:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="buttonA"
        android:visibility="gone"
        />

    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="buttonB"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/buttonA"
        app:layout_goneMarginLeft="40dp"
        />
</android.support.constraint.ConstraintLayout>
2-1

3、Chains(鏈)
鏈使我們能夠對一組在水平或豎直方向互相關聯的控件的屬性進行統一管理。成為鏈的條件:一組控件它們通過一個雙向的約束關系鏈接起來,首尾對parent約束。 并且鏈的屬性是由一條鏈的頭結點控制的,如下:


3-1

Chains Style:鏈的樣式有三種packed,spread_inside,spread

 app:layout_constraintHorizontal_chainStyle="packed | spread_inside | spread"
3-2
  • Spread Chain:Style為spread的時候。
  • Spread Chain:Style為spread_inside的時候。
  • Weighted Chain:當Style為spread,width為0dp,可以使用Weighted屬性等分(Weighted屬性和線性布局的weighted用法相同)
  • Packed Chain 當Style為packed的時候。
  • Packed Chain with Bias,當Style為packed,并且設置了Bias屬性。Bias屬性下部分會講解
<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/bt_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintEnd_toStartOf="@+id/bt_2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/bt_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B"
        app:layout_constraintEnd_toStartOf="@+id/bt_3"
        app:layout_constraintStart_toEndOf="@+id/bt_1"
        app:layout_constraintTop_toTopOf="@+id/bt_1" />

    <Button
        android:id="@+id/bt_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="c"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/bt_2"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

4、MATCH_CONSTRAINT
上邊我們說過ConstraintLayout取消了MATCH_PARENT由MATCH_CONSTRAINT來代替,默認大小占用所有約束可用空間,并提供了以下屬性輔助我們使用。

  • layout_constraintWidth_min 設置最小寬度
  • layout_constraintHeight_min 設置最小高度
  • layout_constraintWidth_max 設置最大寬度
  • layout_constraintHeight_max 設置最大高度
  • layout_constraintWidth_percent 設置寬度相對父類寬度百富比
  • layout_constraintHeight_percent 設置高度相對父類高度的百分比

5、百分比布局
約束布局支持子控件設置寬高比,前提條件是至少需要將寬高中的一個設置為0dp。為了約束一個特定的邊,基于另一個邊的尺寸,可以預先附加W,或H以逗號隔開。

<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:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="0dp"
        android:layout_height="0dp"http://高度基于寬度的尺寸所以高度為0dp,否則百分比屬性無效
        android:text="A"
        app:layout_constraintDimensionRatio="H,16:9"http://約束高度基于寬度的尺寸。
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
5-1

6、Guideline 輔助線
Guideline輔助線是一條寬或高為0dp的一個看不見的線,和LinearLayout一樣都有orientation屬性設置橫向或垂直。有三種定位方式

  • layout_constraintGuide_begin 距離父容器起始位置的距離(左側或頂部)垂直的輔助線使用
  • layout_constraintGuide_end 距離父容器結束位置的距離(右側或底部)水平的輔助線使用
  • layout_constraintGuide_percent 距離父容器寬度或高度的百分比(垂直或水平的輔助線都可以使用)

例:設置一條垂直方向距離父控件左側為100dp的Guideline:

<android.support.constraint.Guideline
        android:layout_width="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="100dp"
        android:layout_height="wrap_content"/>

7、Group為ConstraintLayout布局中的子控件進行分組,可控制多個布局控件統一的可見性

    <android.support.constraint.Group
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"http://設置可見性
        app:constraint_referenced_ids="bt1,bt2"http://要管理的控件id
       />
        <Button
            android:id="@+id/bt1"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:text="A"
            />
        <Button
            android:id="@+id/bt2"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:text="A"
            />

8、Barrier,屏障,在約束布局中,可以將幾個View作為一個整體來使用,讓其他布局關聯約束這個整體。注意設置他的visibility不能控制這個整體的可見性。我們看一個例子。

<TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="姓名:"
        app:layout_constraintBottom_toBottomOf="@+id/et_name"
        app:layout_constraintTop_toTopOf="@+id/et_name"/>

    <TextView
        android:id="@+id/tv_contract"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="聯系方式:"
        app:layout_constraintBottom_toBottomOf="@+id/et_contract"
        app:layout_constraintTop_toTopOf="@+id/et_contract"/>

    <EditText
        android:id="@+id/et_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="請輸入姓名"
        app:layout_constraintLeft_toLeftOf="@+id/barrier"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <EditText
        android:id="@+id/et_contract"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="請輸入聯系方式"
        app:layout_constraintLeft_toLeftOf="@+id/barrier"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/et_name"/>

    <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="tv_name,tv_contract"/>
8-1

這里我們把A區域中的姓名和聯系方式用Barrier關聯成一個整體。而右側的B區域中的EditText分別關聯約束這個Barrier整體。當Barrier整體中的TextView的寬度發生改變時,Barrier整體也是變化的,右側的B區域的寬度也會隨之改變。
9、Circular positioning (圓形定位)

  • 您可以將一個控件的中心以一定的角度和距離約束到另一個控件的中心,相當于在一個圓上放置一個控件。
<Button android:id="@+id/buttonA" ... />
  <Button android:id="@+id/buttonB" ...
      //引用的控件ID
      app:layout_constraintCircle="@+id/buttonA"
      //圓半徑
      app:layout_constraintCircleRadius="100dp"
      //偏移圓角度  水平右方向為0逆時針方向旋轉
      app:layout_constraintCircleAngle="45" />
9-1

10、bias 權重

  • 當一個控件擁有水平方向(左右兩個約束)或者垂直方向(上下兩個約束)的時候,我們可以通過app:layout_constraintHorizontal_bias
    ="0.16"或 app:layout_constraintVertical_bias="0.303"兩個屬性來對兩個方向的約束進行百分比的調整。讓控件按百分比偏向一方。當不設置是默認是0.5居中的效果。
    <Button
        android:id="@+id/bt1"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:text="A"
        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.2" />
10-1

參考文章:

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容