ConstraintLayout使用詳解 上

傳統(tǒng)布局缺陷

![]這里寫(xiě)圖片描述

<ScrollView>
    <LinearLayout>

        ...
        ...

        <LinearLayout>
        
            <LinearLayout>
                <LinearLayout/>
                <LinearLayout/>
                <LinearLayout/>
                <LinearLayout/>
            </LinearLayout>

            <LinearLayout>
                <LinearLayout/>
            </LinearLayout>

            <LinearLayout>
                <LinearLayout/>
                <LinearLayout/>
            </LinearLayout>
        </LinearLayout>
        
    </LinearLayout>
</ScrollView>

在這樣場(chǎng)景下發(fā)現(xiàn)最多的時(shí)候用到四層線性布局,共嵌套了五層丹允,即使使用RelativeLayout和LinearLayout結(jié)合使用的方式,最少也需要三層的布局袋倔,在面對(duì)復(fù)雜界面的時(shí)候雕蔽,這樣實(shí)現(xiàn)往往造成布局不夠扁平,繪制性能也低下宾娜。

傳統(tǒng)布局的缺點(diǎn)

  • 復(fù)雜布局能力差批狐,需要不同布局嵌套使用。
  • 布局嵌套層級(jí)高前塔。不同布局的嵌套使用嚣艇,導(dǎo)致布局的嵌套層級(jí)偏高。
  • 頁(yè)面性能低华弓。較高的嵌套層級(jí)食零,需要更多的計(jì)算布局時(shí)間,降低了頁(yè)面性能寂屏。
  • 按固定寬高比布局等更高階的布局需求贰谣,原先的各類布局方式都不能很好的支持,可能需要通過(guò)Java代碼迁霎,在運(yùn)行中二次實(shí)現(xiàn)吱抚。

因此我們需要一個(gè)更加優(yōu)雅的實(shí)現(xiàn)方式。

ConstraintLayout的出現(xiàn)

在2016年Google I/O大會(huì)時(shí)提出考廉,2017年2月發(fā)布正式版

A ConstraintLayout is a ViewGroup which allows you to position and size widgets in a flexible way.

Note: ConstraintLayout is available as a support library that you can use on Android systems starting with API level 9 (Gingerbread). As such, we are planning on enriching its API and capabilities over time. This documentation will reflect those changes.

Android Studio雖然提供了可視化編寫(xiě)UI的功能频伤,但是在ConstraintLayout出來(lái)之前,我認(rèn)為它一直是雞肋的存在芝此,好無(wú)體驗(yàn)可言憋肖,開(kāi)發(fā)過(guò)ios的都知道xCode 神器storyboard的便利之處,畫(huà)UI幾乎美工都可以完成婚苹,所見(jiàn)即所得岸更,主要還是依賴了ios布局的大量的約束條件,ConstraintLayout的引入解決了Android界面編寫(xiě)的很多痛點(diǎn)膊升,從名字就可以看出怎炊,約束布局通過(guò)豐富的約束條件可以達(dá)到降低頁(yè)面布局層級(jí)、提升頁(yè)面渲染性能的目的。精心使用完全可以替代其他布局评肆。

ConstraintLayout的使用

引入

  • 在項(xiàng)目build.gradle文件中引入maven倉(cāng)庫(kù)

repositories {
maven {
url 'https://maven.google.com'
}
}
```

  • 在APP build.gradle中依賴約束布局庫(kù)

    compile 'com.android.support.constraint:constraint-layout:1.0.2'

  • 在布局文件中ConstraintLayout要使用

    xmlns:app="http://schemas.android.com/apk/res-auto"

下面的介紹根據(jù)Android文檔進(jìn)行擴(kuò)展

Relative positioning 相對(duì)定位

Relative positioning is one of the basic building block of creating layouts in ConstraintLayout. Those constraints allow you to position a given widget relative to another one. You can constrain a widget on the horizontal and vertical axis:

  • Horizontal Axis: left, right, start and end sides
  • Vertical Axis: top, bottom sides and text baseline
屬性名 含義
layout_constraintLeft_toLeftOf 左邊緣和xx左邊緣對(duì)齊
layout_constraintLeft_toRightOf 左邊緣和xx右邊緣對(duì)齊
layout_constraintRight_toLeftOf 右邊緣和xx左邊緣對(duì)齊
layout_constraintRight_toRightOf 右邊緣和xx右邊緣對(duì)齊
layout_constraintTop_toTopOf 上邊緣和xx上邊緣對(duì)齊
layout_constraintTop_toBottomOf 上邊緣和xx下邊緣對(duì)齊
layout_constraintBottom_toTopOf 下邊緣和xx上邊緣對(duì)齊
layout_constraintBottom_toBottomOf 下邊緣和xx下邊緣對(duì)齊
layout_constraintBaseline_toBaselineOf 基于baseline對(duì)齊
layout_constraintStart_toEndOf 起始邊緣和xx結(jié)束邊緣對(duì)齊
layout_constraintStart_toStartOf 起始邊緣和xx起始邊緣對(duì)齊
layout_constraintEnd_toStartOf 結(jié)束邊緣和xx起始邊緣對(duì)齊
layout_constraintEnd_toEndOf 結(jié)束邊緣和xx結(jié)束邊緣對(duì)其

嚯溺蕉,一眼看上去ConstraintLayout的屬性名也太長(zhǎng)了吧骑祟,根本沒(méi)法記啊,我一開(kāi)始也是這么認(rèn)為的,官方給出了解釋:

They all take a reference id to another widget, or the parent (which will reference the parent container, i.e. the ConstraintLayout)

總結(jié)規(guī)律就是屬性名里面constraintxxx就是我當(dāng)前控件的某條邊緣组题,toxxxof是我指定的另一個(gè)布局或控件的某條邊緣则剃,作用就是這兩個(gè)邊緣之間的相對(duì)關(guān)系茵肃。如果參照對(duì)象是parent布局诉儒,則可以完成和父布局邊緣對(duì)齊的操作。例如layout_constraintLeft_toLeftOf = "parent"則是居左淆衷。

  • 這里baseline做一個(gè)說(shuō)明缸榄,baseline是文字的基線,可以參照某個(gè)控件(i.e. Button)中文字下邊緣對(duì)齊祝拯。

    這里寫(xiě)圖片描述

Margins 邊距

屬性和傳統(tǒng)布局相同甚带,這里就不多解釋

屬性名
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom

Margins when connected to a GONE widget 和 隱藏空間設(shè)置邊距

When a position constraint target's visibility is View.GONE, you can also indicate a different margin value to be used using the following attributes:

可以和可見(jiàn)性已被設(shè)為View.GONE的控件設(shè)置邊距,常用于在相對(duì)布局中保持各個(gè)控件的位置佳头。因?yàn)槲覀冊(cè)陂_(kāi)發(fā)中常常遇到一個(gè)空間被設(shè)為GONE之后鹰贵,和他有相對(duì)關(guān)聯(lián)的控件的位置會(huì)發(fā)生改變,影響了原有的布局畜晰,導(dǎo)致UI混亂砾莱,用以下屬性可以保持原有設(shè)計(jì):

屬性名
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom

Centering positioning and bias 居中定位和偏移

  • center_vertical
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
  • center_horizontal
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
  • center
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
  • bias

    有人會(huì)說(shuō)我線性布局一行代碼實(shí)現(xiàn)居中,你這也太太太啰嗦了凄鼻,naive腊瑟,下面才是約束布局的新特性,一行代碼實(shí)現(xiàn)固定比例偏移块蚌。比如下面這個(gè)場(chǎng)景闰非,我要讓A左右兩邊的空檔寬度比例為3:7:

    這里寫(xiě)圖片描述

    在沒(méi)了解ConstraintLayout之前,你一定會(huì)想到用LinearLayout配合layout_weight來(lái)完成:

        <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:orientation="horizontal">
    
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"
            android:background="@color/colorAccent" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按鈕" />
    
        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="7"
            android:background="@color/colorAccent" />
    </LinearLayout>
    

    一頓操作猛如虎峭范,一看代碼卻很俗

    怎么更加優(yōu)雅的實(shí)現(xiàn)這樣的場(chǎng)景呢财松,ConstraintLayout給出了答案:

    屬性名 |
    ------------- |
    layout_constraintHorizontal_bias|水平便宜比例
    layout_constraintVertical_bias|豎直便宜比例
    一行代碼便可實(shí)現(xiàn) 666:

    <android.support.constraint.ConstraintLayout ...>
                 <Button android:id="@+id/button" ...
                     app:layout_constraintHorizontal_bias="0.3"
                     app:layout_constraintLeft_toLeftOf="parent"
                     app:layout_constraintRight_toRightOf="parent/>
    </>
    

牛X的還不僅于此,收起下巴纱控,下面的更強(qiáng)大

Circular positioning (Added in 1.1) 1.1版本特性 圓弧定位(自己翻譯)

You can constrain a widget center relative to another widget center, at an angle and a distance. This allows you to position a widget on a circle.

可以根據(jù)兩個(gè)空間的中心位置形成約束關(guān)系辆毡,以當(dāng)前組件中心為圓心設(shè)置半徑和角度來(lái)設(shè)置約束條件

這里寫(xiě)圖片描述
這里寫(xiě)圖片描述
屬性名 含義
layout_constraintCircle 引用另一個(gè)控件id
layout_constraintCircleRadius 到xx中心位置的距離,即圓周半徑
layout_constraintCircleAngle xx所在圓周的角度(0-360)
<Button android:id="@+id/buttonA" ... />
  <Button android:id="@+id/buttonB" ...
      app:layout_constraintCircle="@+id/buttonA"
      app:layout_constraintCircleRadius="100dp"
      app:layout_constraintCircleAngle="45" />

Dimensions constraints 維度約束

  • ConstraintLayout自身約束
屬性名 含義
android:minWidth set the minimum width for the layout
android:minHeight set the minimum height for the layout
android:maxWidth set the maximum width for the layout
android:maxHeight set the maximum height for the layout

注意上述屬性設(shè)置ConstraintLayout本身最大最小尺寸只適用于自身為WRAP_CONTENT下

Percent dimension 百分比維度

可以設(shè)置控件相對(duì)于父布局尺寸的百分比甜害,0-1之間舶掖。需要注意:

  • 控件的width和height要被設(shè)置為0dp
  • 默認(rèn)寬高屬性要被設(shè)置為percent(1.1版本之后將無(wú)需設(shè)置,自動(dòng)識(shí)別)
app:layout_constraintWidth_default="percent"
app:layout_constraintHeight_default="percent" 
 <Button
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintWidth_percent="0.3"
        app:layout_constraintHeight_percent="0.2"
        />

設(shè)置按鈕的寬度為父布局寬度的30%尔店,高度為父布局高度的20%眨攘。

Ratio 比例

可以定義一個(gè)控件寬高尺寸比例主慰,這樣可以固定控件的尺寸關(guān)系,形成一種約束鲫售,減少出現(xiàn)UI混亂被擠壓的情況共螺,可以形成自適應(yīng)。但是要注意的事情竹,控件的兩個(gè)維度height和width中至少要有一個(gè)設(shè)置為0或者M(jìn)ATCH_CONSTRAINT藐不,這個(gè)很好理解,不解釋鲤妥。

<Button android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintDimensionRatio="1:1" />

這樣就可以不用指定一個(gè)正方形的寬高佳吞,設(shè)計(jì)合理的話可以根據(jù)屏幕自適應(yīng)拱雏。

同樣棉安,也可以只限制其中一個(gè)維度(height或width)隨另一個(gè)維度的變化的比例。
如果一個(gè)維度固定铸抑,只需要在比例前面加上“H"或者”W"表示想要對(duì)哪個(gè)維度進(jìn)行限制贡耽。

 <Button android:layout_width="0dp"
         android:layout_height="0dp"
         app:layout_constraintDimensionRatio="H,16:9"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintTop_toTopOf="parent"/>

上面代碼中按鈕的width將會(huì)充滿父布局,而高度則會(huì)以16:9的比例進(jìn)行測(cè)量繪制鹊汛。

Chains 鏈

chain是ConstraintLayout的新概念蒲赂,可以讓多個(gè)組件在一個(gè)方向上(水平或豎直)組合成一個(gè)集體,官方稱 provide group-like behavior刁憋。
我們知道滥嘴,以往的控件之間的相對(duì)聯(lián)系是一個(gè)控件A基于另一個(gè)控件B的位置關(guān)聯(lián),控件A隨著B(niǎo)的變動(dòng)變動(dòng)若皱,反之則不行尘颓,但是Chain的存在,可以說(shuō)是一個(gè)組合疤苹,讓多個(gè)控件組成了一個(gè)集體互广,一直保持固定的相對(duì)關(guān)系,這樣做的好處是可以減少布局兼容時(shí)造成的混亂惫皱,方便整體復(fù)用尤莺。

  • 創(chuàng)建一個(gè)鏈約束

    鏈約束的關(guān)鍵在于需要組合在一起的布局之間在同一個(gè)方向上是雙向連接旅敷,也就是相互進(jìn)行相對(duì)約束。

    這里寫(xiě)圖片描述

    對(duì)于 A缝裁、B兩個(gè)button扫皱,形成鏈約束代碼如下:

    <Button
            android:id="@+id/btn1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="A"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@id/btn2" />
    
    <Button
            android:id="@+id/btn2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="B"
            app:layout_constraintLeft_toRightOf="@id/btn1"
            app:layout_constraintRight_toRightOf="parent" />
    
    這里寫(xiě)圖片描述
  • chain heads 鏈頭

    鏈?zhǔn)怯涉溕系谝粋€(gè)元素(鏈頭)上的屬性集控制韩脑,鏈頭是最左邊或最上邊的組件。

    這里寫(xiě)圖片描述
  • chain style 鏈內(nèi)布局方式

    layout_constraintHorizontal_chainStyle 水平鏈內(nèi)布局方式

    layout_constraintVertical_chainStyle 豎直鏈內(nèi)布局方式

    只要在鏈頭組件設(shè)置chain style首量,便可以控制整條鏈的內(nèi)部組件排列布局方式进苍。

    默認(rèn)style為CHAIN_SPREAD,即組件間隔均分可使用空間觉啊。

    這里寫(xiě)圖片描述

    ?

性能比較

由于ConstraintLayout天生扁平的優(yōu)點(diǎn)杠人,在性能上肯定要優(yōu)于傳統(tǒng)布局不少,關(guān)于性能對(duì)比的詳細(xì)情況嗡善,可以查看這篇文章了解使用 ConstraintLayout 的性能優(yōu)勢(shì)

布局編輯器(待更新)

代碼設(shè)置布局(待更新)

源碼解析(待更新)

參考文獻(xiàn)

1、 官方文檔

2各吨、Android新特性介紹袁铐,ConstraintLayout完全解析 郭霖

3、ConstraintLayout入門(mén)指南 QQ音樂(lè)技術(shù)團(tuán)隊(duì)

4忌锯、ConstraintLayout在項(xiàng)目中實(shí)踐與總結(jié)

5领炫、了解使用 ConstraintLayout 的性能優(yōu)勢(shì)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末偶垮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子似舵,更是在濱河造成了極大的恐慌葱峡,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛛芥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡仅淑,警方通過(guò)查閱死者的電腦和手機(jī)涯竟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)银酬,“玉大人筐钟,你說(shuō)我怎么就攤上這事∽尘拢” “怎么了纹因?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵琳拨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我惊畏,道長(zhǎng)密任,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任缰盏,我火速辦了婚禮淹遵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘济炎。我一直安慰自己辐真,他們只是感情好崖堤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布倘感。 她就那樣靜靜地躺著咙咽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钧敞。 梳的紋絲不亂的頭發(fā)上溉苛,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音娇唯,去河邊找鬼寂玲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛拓哟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播流纹,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼漱凝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼诸迟!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起亮蒋,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤慎玖,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后湿硝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡示括,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年痢畜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吼拥。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡线衫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出枯跑,到底是詐尸還是另有隱情白热,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布辜腺,位于F島的核電站乍恐,受9級(jí)特大地震影響测砂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呜投,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一存璃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粘招,春花似錦偎球、人聲如沸辑甜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至煌恢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缩歪,已是汗流浹背谍憔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逛球,地道東北人苫昌。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像奥务,于是被迫代替她去往敵國(guó)和親袜硫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容