ConstraintLayout簡介
一種應(yīng)對復(fù)雜多層嵌套或復(fù)雜依賴關(guān)系的高效布局,解決相對布局中由于目標(biāo)控件隱藏導(dǎo)致的布局混亂而被迫嵌套布局的問題媒咳,解決權(quán)重百分比布局時LinearLayout的不足紫皇,并且提供特殊布局方式草丧,如圓形布局、特殊疊加擺放等轰绵。
學(xué)習(xí)本布局的目標(biāo)是實現(xiàn)不嵌套的復(fù)雜布局粉寞。
本系列學(xué)習(xí)心得,先講解基本用法左腔,然后逐步進行進階實戰(zhàn)UI效果的實現(xiàn)仁锯,采坑之路的心得等。
低版本用Compile翔悠,關(guān)鍵字业崖。高版本Android Studio如下
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
如下圖方法數(shù)統(tǒng)計圖,所以對整個項目的包大小不構(gòu)成威脅蓄愁,可以放心食用双炕,入口有點甜。
目錄
- 基礎(chǔ)屬性介紹
- 相對擺放
- 水平居中以及權(quán)重居中
- Margin間距失效
- 目標(biāo)依賴約束對象隱身術(shù)
- 圓形布局
- 寬高約束
- Guideline
- 鏈?zhǔn)讲季?/li>
- 布局分組-控制可見性
基礎(chǔ)屬性介紹
大家應(yīng)該熟悉相對布局RelativeLayout撮抓,有很多belowOf妇斤,rightOf類似的屬性,用于做控件之間相對定位布局丹拯。所以開篇我們先講這個基礎(chǔ)屬性站超,如何在ConstraintLayout布局內(nèi),進行相對定位乖酬。
屬性名 | 簡介 |
---|---|
layout_constraintLeft_toLeftOf | 當(dāng)前控件A左側(cè)依賴于目標(biāo)約束對象B的左側(cè)死相,簡單點 就是A左靠近B左側(cè)對齊 |
layout_constraintLeft_toRightOf | 當(dāng)前控件A左側(cè)依賴于目標(biāo)約束對象B的右側(cè),簡單點 就是A左靠近B右側(cè)對齊 |
layout_constraintRight_toLeftOf | 當(dāng)前A右側(cè)靠近B左側(cè)對齊咬像,接下來的屬性類似... |
layout_constraintRight_toRightOf | |
layout_constraintTop_toTopOf | |
layout_constraintTop_toBottomOf | |
layout_constraintBottom_toTopOf | |
layout_constraintBottom_toBottomOf | |
layout_constraintBaseline_toBaselineOf | 文本基準(zhǔn)線對齊 |
layout_constraintStart_toEndOf | 當(dāng)前控件A起始邊與目標(biāo)約束對象B尾部對齊 |
layout_constraintStart_toStartOf | 當(dāng)前控件A起始邊與目標(biāo)約束對象B起始邊對齊算撮,下面類似 |
layout_constraintEnd_toStartOf | |
layout_constraintEnd_toEndOf |
如上所述生宛,常見的基本屬性就是這些,我們先學(xué)習(xí)這些近似相對布局的屬性肮柜。理解上述屬性的宗旨是陷舅,把當(dāng)前控件分為上下左右四個方向,在不同的情況下根據(jù)UI圖审洞,進行相對約束申明莱睁。
常用特性介紹
1. 相對擺放
下面2個控件Button1在父布局右上角,button2只申明在button1的下方芒澜。跟相對布局一樣缩赛,Android坐標(biāo)默認(rèn)是中心點在左上角,所以不申明水平約束撰糠,會默認(rèn)讓Button2在左側(cè)。
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
android:id="@+id/button1"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="我在右上角"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/button2"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="我在他下面"
app:layout_constraintTop_toBottomOf="@id/button1"/>
</android.support.constraint.ConstraintLayout>
2. 水平居中以及權(quán)重居中
下面開始進階使用辩昆,如何水平居中阅酪。在下圖中的ConstraintLayout下,Button控件就像是橡皮泥汁针,多重約束控制時术辐,會被拉伸。比如view的左側(cè)要貼住父布局左側(cè)施无,view的右側(cè)又要靠近父布局右側(cè)辉词,這樣view只好在中間開始被向兩邊拉伸。這個就跟你在媳婦和公婆之間糾結(jié)一樣猾骡,兩邊都要你表態(tài)瑞躺,哈哈。但是人是有私心的兴想,又要偏袒一方幢哨,或者一方一直處于劣勢,要維護下嫂便,所以又出現(xiàn)bias概念捞镰。如下圖,雖然是水平居中毙替,但是button2明顯偏向某一方岸售,0-1的權(quán)重值,越大就越靠近右側(cè)厂画。當(dāng)然你想玩得轉(zhuǎn)凸丸,設(shè)置0.5,兩邊不偏袒(我一條狗為啥說這個)袱院。這里說的是水平居中實現(xiàn)方式甲雅,至于垂直居中和父布局居中類似解孙,依樣畫葫蘆,自行實踐抛人。紅色的TextView展示如何平鋪填滿寬度弛姜,設(shè)置0dp(match_constraint )代表matchParent。
<?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"
tools:context=".MainActivity">
<Button
android:id="@+id/button1"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="水平居中"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<Button
android:id="@+id/button2"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginTop="60dp"
android:text="水平居中后偏向某一側(cè)"
app:layout_constraintHorizontal_bias="0.6"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/button3"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:background="@color/colorAccent"
android:gravity="center"
android:text="水平填滿"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/button2"/>
</android.support.constraint.ConstraintLayout>
3. Margin間距失效
在這里要注意一點妖枚,ConstraintLayout布局中廷臼,我想讓Button2布局不遮擋演示的Button1,直接設(shè)置
android:layout_marginTop="60dp"是不行的绝页。如下圖荠商,沒有變更位置,控件依然遮擋Button1.
<Button
android:id="@+id/button2"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginTop="60dp"
android:text="水平居中后偏向某一側(cè)"
app:layout_constraintHorizontal_bias="0.6"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
通過上面實踐發(fā)現(xiàn)续誉,沒有申明某一邊的約束目標(biāo)對象(比如這里是parent)莱没,設(shè)置對應(yīng)的邊的margin不起作用。比如我button1是有左側(cè)約束對象的酷鸦,此時設(shè)置300dp左間距饰躲,生效!
<Button
android:id="@+id/button1"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginLeft="300dp"
android:text="水平居中"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
4. 目標(biāo)依賴約束對象隱身術(shù)
在UI實現(xiàn)中臼隔,有很多控件是在某一些場景下才會顯示嘹裂,但是布局肯定又得把它寫進去。然后顯示時摔握,它又要占據(jù)當(dāng)前常規(guī)情況下的控件的位置寄狼,需要調(diào)整這個常規(guī)控件向左或者向右移動位置。這種目標(biāo)隱身術(shù)氨淌,平常通過對這2個控件進行LinearLayout嵌套等方式去實現(xiàn)泊愧,很不好辦。下面介紹隱身術(shù)的應(yīng)對辦法,goneMargin大法盛正。
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
我在布局里拼卵,要求button1在最上面,button2和button3要相對button1在它下面蛮艰,當(dāng)button2顯示時腋腮,button3要在button2下面。此時就需要這樣布局了壤蚜。
<?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/button1"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="你們跟著我"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/button2"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginTop="100dp"
android:text="我是2.我在他下面"
android:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/button1"/>
<Button
android:id="@+id/button3"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="我是3.我在他下面"
app:layout_constraintTop_toBottomOf="@id/button2"
/>
</android.support.constraint.ConstraintLayout>
接下來我再設(shè)置 android:visibility="gone"即寡,隱藏button2,神奇的一幕發(fā)生了袜刷。此時button2消失后聪富,button2的marginTop100dp也沒了,button3仍然保持button2之前對button1的依賴約束著蟹。
那么如果我還想要維持之前的100dp怎么辦墩蔓,設(shè)置button3的marginTop為100dp梢莽,不行,會變成下面圖的樣子奸披。
這個時候就請出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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="你們跟著我"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/button2"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginTop="100dp"
android:text="我是2.我在他下面"
android:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/button1"/>
<Button
android:id="@+id/button3"
android:layout_width="150dp"
android:layout_height="50dp"
app:layout_goneMarginTop="100dp"
android:text="我是3.我在他下面"
app:layout_constraintTop_toBottomOf="@id/button2"
/>
</android.support.constraint.ConstraintLayout>
設(shè)置button2消失后阵面,如下圖
OK轻局,一切如我們想要的效果一樣,完美样刷。那么如果我不需要在button2消失后仑扑,保持這么多間距呢,
app:layout_goneMarginTop改下即可置鼻,實際業(yè)務(wù)場景經(jīng)常有這種需要镇饮,上方的布局消失后,與頂部間距有不一樣的間距箕母,此時goneMargin就發(fā)揮大作用了储藐。不用自己代碼里搞事情去實現(xiàn)動態(tài)區(qū)分布局。
5. 圓形布局
實現(xiàn)星星環(huán)繞效果的布局司蔬,一看這個效果,開發(fā)頭都大了姨蝴,自定義layout group俊啼?不不不,我們有新的真愛來救我們了左医。圓形布局大法幫你實現(xiàn)各種吊炸天的設(shè)計效果圖授帕。另外也可實現(xiàn)頭像右上角角標(biāo)效果。
layout_constraintCircle :依賴哪個控件進行布局
layout_constraintCircleRadius :到依賴對象中心的距離
layout_constraintCircleAngle :當(dāng)前要擺放的控件應(yīng)處于哪個角度(度數(shù)浮梢,從0到360)
廢話不多說跛十,show you fuck code。
<?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/button1"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="垂直居中"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Button
android:id="@+id/button2"
android:layout_width="50dp"
android:layout_height="50dp"
android:text="A"
app:layout_constraintCircle="@+id/button1"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="70dp"/>
<Button
android:id="@+id/button3"
android:layout_width="50dp"
android:layout_height="50dp"
android:text="B"
app:layout_constraintCircle="@+id/button1"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="70dp"/>
<Button
android:id="@+id/button4"
android:layout_width="50dp"
android:layout_height="50dp"
android:text="C"
app:layout_constraintCircle="@+id/button1"
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="70dp"/>
</android.support.constraint.ConstraintLayout>
上圖我們實現(xiàn)了A在45°方向擺放秕硝,并且靠近依賴約束的對象的中心點70dp芥映,B和C類似,跟A間隔45°擺放远豺,一種星星環(huán)繞效果實現(xiàn)好了奈偏。想想以前怎么實現(xiàn),是不是淚奔躯护。惊来。。組織上來拯救我們了棺滞,給google遞茶裁蚁,遞辣條矢渊!
6. 寬高約束
很多時候我們需要設(shè)置最大寬度和高度,或者最小寬度或高度枉证。那么在ConstraintLayout里矮男,我們將接觸多種限制手段。
屬性 | 簡介 |
---|---|
layout_constraintWidth_min和layout_constraintHeight_min | 設(shè)置寬高的最小值 |
layout_constraintWidth_max和layout_constraintHeight_max | 設(shè)置寬高的最大值 |
layout_constraintWidth_percent和layout_constraintHeight_percent | 設(shè)置寬高的比例值刽严,需要設(shè)置寬高layout_width昂灵、layout_height屬性為MATCH_CONSTRAINT(0dp) |
除了上述屬性外,1.1版本開始新增加WRAP_CONTENT時的強制約束特性舞萄,下圖中眨补,由于WRAP_CONTENT時,寬高約束失效倒脓,第一個控件雖然申明了最大寬度撑螺,但是并沒有起作用。但是第二個控件 app:layout_constrainedWidth="true"設(shè)置后崎弃,寬度被限制在200dp甘晤。
//屬性
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="我的寬度被限制了,但是不起作用我的寬度被限制了,但是不起作用我的寬度被限制了,但是不起作用"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_max="200dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="100dp"
android:maxWidth="100dp"
android:text="寬度限制起作用了,寬度限制起作用了寬度限制起作用了寬度限制起作用了"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/button1"
app:layout_constraintWidth_max="200dp"/>
</android.support.constraint.ConstraintLayout>
此外饲做,可以設(shè)置寬高的比例线婚,比如16:9.下圖文本顯示“111”控件是16:9的效果,"H,16:9"代表約束高度,且保持寬高比16:9盆均;根據(jù)上面的學(xué)習(xí)塞弊,寬度0dp時,設(shè)置了左邊和右邊的依賴約束對象為parent泪姨,所以寬度是已知的充滿屏幕游沿;利用已知的寬計算出 高度=寬度*16/9。
對于這一塊肮砾,我也是有很多疑問诀黍,還沒完全理解,等理解后仗处,再對ratio進行詳細解釋眯勾。下面這一句是別人貼出來的。
In this case the system sets the largest dimensions the satisfies all constraints and maintains the aspect ratio specified.
<?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">
<TextView
android:id="@+id/tv1"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/colorAccent"
android:text="1111111"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/tv2"
android:layout_width="100dp"
android:layout_height="0dp"
android:background="#cccccc"
android:gravity="center"
android:text="22222"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:4"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:layout_width="0dp"
android:layout_height="100dp"
android:background="@color/colorPrimary"
android:text="4444444"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="W,1:4"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:layout_width="0dp"
android:layout_height="30dp"
android:background="@color/colorPrimary"
android:text="55555"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:4"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:layout_width="100dp"
android:layout_height="0dp"
android:background="@color/colorPrimary"
android:text="333333"
app:layout_constraintHeight_percent="0.3"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</android.support.constraint.ConstraintLayout>
7. Guideline
有些時候UI效果把界面化為幾個區(qū)域婆誓,A區(qū)域會根據(jù)B區(qū)域的寬度而動態(tài)調(diào)整位置咒精。或者有時候旷档,某些控件要作為一個整體在同一垂直方向都居中(這些控件在同一個X坐標(biāo))模叙,但是以前的相對布局單純設(shè)置垂直居中就會被疊加。比如下圖效果鞋屈,1和2控件都要在垂直居中范咨,使用Guideline可以愉快的解決這些問題故觅。其中的 app:layout_constraintGuide_percent="0.5"表示在垂直方向50%的位置。
<?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">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"
/>
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorAccent"
android:text="1111"
app:layout_constraintBottom_toTopOf="@id/guideline"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@color/colorPrimary"
android:text="2222"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/guideline"/>
</android.support.constraint.ConstraintLayout>
8. 鏈?zhǔn)讲季?/h5>
當(dāng)AB控件相互之間建立依賴約束時渠啊,比如A申明右邊與B的左邊約束输吏,B同樣申明,形成一個回路替蛉,就產(chǎn)生了鏈AB贯溅。比如官網(wǎng)的下圖
其中第一個申明的控件作為鏈頭,所有鏈的屬性在鏈頭申明躲查,比如chainstyle它浅。根據(jù)官網(wǎng)的圖,chainstyle有下面幾種镣煮,默認(rèn)是spread姐霍。
重點講下權(quán)重鏈,類似于linearlayout的weight使用典唇,但是比它要更強大镊折。設(shè)置0dp(MATCH_CONSTRAINT)的鏈內(nèi)控件將瓜分剩余可用控件,根據(jù)權(quán)重值介衔,分割不同的大小恨胚。如下圖,Button1和button2設(shè)置了0dp,因為button1設(shè)置了做間距80dp炎咖,瓜分剩余空間是在這個區(qū)域右側(cè)赃泡。由于未設(shè)置具體權(quán)重,所以2者均分塘装。而button3急迂、button4影所、button5不一樣蹦肴,button5設(shè)置了50dp寬度,但是未設(shè)置權(quán)重猴娩,而butto3和button4分別設(shè)置了1阴幌、2的權(quán)重值,所以button4是button3的2倍大小卷中。
<?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/button1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:text="Button1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/button2"/>
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintLeft_toRightOf="@+id/button1"
app:layout_constraintRight_toRightOf="parent"/>
<Button
android:id="@+id/button3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/button4"/>
<Button
android:id="@+id/button4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintLeft_toRightOf="@+id/button3"
app:layout_constraintRight_toLeftOf="@+id/button5"
/>
<Button
android:id="@+id/button5"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="Button5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/button4"
app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>
9. 布局分組-控制可見性
利用constraint.Group對布局里的控件進行分組矛双,app:constraint_referenced_ids里申明同一組的控件。
看源碼其實group類繼承ConstraintHelper蟆豫,最終繼承的view议忽。我們通過referenced_ids屬性設(shè)置的id數(shù)組最終被它存放,最終updatePreLayout方法遍歷設(shè)置可見或不可見等十减。比如下圖栈幸,我button1所在的group設(shè)置了invisible,button2保持了與button1的約束愤估。而左下角放置的2個button都因為group設(shè)置了gone,導(dǎo)致隱藏了速址。值得注意的是玩焰,一旦被設(shè)置到某個分組group控件里,子控件本身的visibility屬性就不起作用了芍锚,group設(shè)置的隱藏和可見才是最終的效果昔园,默認(rèn)group是顯示。
<?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">
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:constraint_referenced_ids="button1"/>
<android.support.constraint.Group
android:id="@+id/group2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:constraint_referenced_ids="button3,button4"/>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:text="Button1"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/button2"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintLeft_toRightOf="@+id/button1"
app:layout_constraintRight_toRightOf="parent"/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/button3"
/>
</android.support.constraint.ConstraintLayout>
而看源碼group并炮,像space控件一樣draw()為空默刚,沒有繪制動作,性能上沒有什么負擔(dān)渣触。在上面介紹的Guideline也是同樣如此羡棵,
public void onDraw(Canvas canvas) {
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (this.mUseViewMeasure) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
this.setMeasuredDimension(0, 0);
}
}
10. Barrier
如果A控件要同時在B和C的右側(cè),而B和C又長度不一定嗅钻,此時相對布局無法確定A到底寫誰右側(cè)好皂冰,而只能嵌套一個層,然后A在B和C的父布局右側(cè)养篓,這樣很不好秃流,所以Barrier界線就是拿來做這種特殊布局的。
<?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/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:text="Button1-111111111111"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:text="Button2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button1"/>
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="button1,button2"/>
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Button3"
app:layout_constraintLeft_toRightOf="@id/barrier"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
下面是在具體實踐中的一種UI效果事例柳弄,僅供參考練習(xí)舶胀。整個布局只有一層,避免了嵌套過審的問題碧注∠ィ“張三”和下面的轉(zhuǎn)圈圖片以及“我放學(xué)了”文本提示都是要求作為一個整體垂直居中,如果常規(guī)的布局萍丐,需要把這三個放到一個容器里一起進行居中轩端,必然存在嵌套,但是約束布局就不需要這樣逝变。下面轉(zhuǎn)圈圖片消失時基茵,我放學(xué)文本提示要自動依賴顯示在左側(cè)方形圖片右側(cè),與張三左對齊壳影,傳統(tǒng)的布局也需要對我放學(xué)了文本和轉(zhuǎn)圈圖片進行嵌套拱层,這樣加上上面的嵌套,導(dǎo)致多了2層嵌套宴咧。
<?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="67dp"
>
<ImageView
android:id="@+id/sdv_chat_dialog_header"
android:layout_width="44dp"
android:layout_height="44dp"
android:layout_marginLeft="16dp"
android:background="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:src="@drawable/ic_launcher_background"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/rrv_remind_unread"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="34dp"
android:gravity="center"
android:includeFontPadding="false"
android:textColor="#ff4444"
app:layout_constraintLeft_toLeftOf="@id/sdv_chat_dialog_header"
app:layout_constraintTop_toTopOf="@id/sdv_chat_dialog_header"
tools:text="9"/>
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="sdv_chat_dialog_header"/>
<android.support.constraint.Guideline
android:id="@+id/guideline_horizontal_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5"
/>
<TextView
android:id="@+id/tv_chat_dialog_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="11dp"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="#000000"
android:textSize="17sp"
app:layout_constraintBottom_toTopOf="@id/guideline_horizontal_center"
app:layout_constraintLeft_toRightOf="@id/barrier"
tools:text="張三"/>
<TextView
android:id="@+id/tv_chat_dialog_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="16dp"
android:includeFontPadding="false"
android:textSize="12sp"
app:layout_constraintBaseline_toBaselineOf="@id/tv_chat_dialog_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="18:05"/>
<ImageView
android:id="@+id/iv_chat_watch_sync"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="11dp"
android:layout_marginRight="5dp"
android:layout_marginTop="2dp"
android:background="@mipmap/ic_synchronization"
android:visibility="visible"
app:layout_constraintLeft_toRightOf="@id/barrier"
app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_center"
/>
<TextView
android:id="@+id/tv_chat_dialog_last_msg_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="#000000"
android:textSize="13sp"
app:layout_constraintLeft_toRightOf="@id/iv_chat_watch_sync"
app:layout_constraintRight_toLeftOf="@id/tv_chat_dialog_update_time"
app:layout_constraintTop_toBottomOf="@id/guideline_horizontal_center"
app:layout_goneMarginLeft="11dp"
tools:text="我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了,我放學(xué)了8888888"/>
<View
android:id="@+id/view_divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="72dp"
android:background="#cccccc"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
結(jié)尾
約束布局也不是一定要完全替代傳統(tǒng)布局根灯,合適的才是最好的。充分利用各種布局的特性滿足UI效果,才是最好的編碼方式烙肺。
到這里芥驳,一些常見的使用已經(jīng)具備了,剩下的就是實戰(zhàn)磨合API茬高,還有一些進階配合使用下一次再講兆旬。
比如ConstraintSet,在代碼里動態(tài)改變約束怎栽,做一些布局動畫丽猬。代碼就不用貼出來,都在上面熏瞄。大家可以在拷貝后脚祟,不斷修改以便熟悉API。