參考
Android新特性介紹,ConstraintLayout完全解析
史上最全ConstraintLayout使用詳解
概述:
約束布局,各個(gè)控件可以依據(jù)某些約束法則排列
位置功能:
相對(duì)位置
相對(duì)父控件位置
layout_constraintBottom_toBottomOf 這樣的結(jié)構(gòu),可以記憶為
layout_constraintBottom 本控件位置指示 底部
toBottomOf 相對(duì)的控制位置指示 底部
app:layout_constraintBottom_toBottomOf="parent" 代表 本控件的底部位置和parent父控件的底部位置一致
一般而已,我們有Bottom,Top,Start,End 幾個(gè)類型,其中Start,End和Left,Right是一致的,只是因?yàn)橛行﹪?guó)家的left和right不是一致的,所以統(tǒng)一用Start,End代表。雖然Start,End和Left,Right是一致的,但是要注意Start,End是一對(duì),Left,Right是一對(duì),不可以混搭使用。
app:layout_constraintBottom_toBottomOf="parent" //本控件的底部位置和parent父控件的底部位置一致
app:layout_constraintEnd_toEndOf="parent"http://本控件的結(jié)束位置和parent父控件的結(jié)束位置一致
app:layout_constraintStart_toStartOf="parent"http://本控件的開始位置和parent父控件的開始位置一致
app:layout_constraintTop_toTopOf="parent"http://本控件的頭部位置和parent父控件的頭部位置一致
下面代碼,就是TextView的位置相對(duì)于父控件位置上下左右都是一致,因?yàn)樗闹芏技s束了,結(jié)果就是再中間
<androidx.constraintlayout.widget.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=".activity.MainActivity">
<TextView
android:id="@+id/imageView"
android:text="TextView 1"
android:background="@color/colorAccent"
android:layout_width="200dp"
android:layout_height="200dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

如果控件沒有約束四邊,就會(huì)有不同的效果,如下圖,只約束了兩邊,控件的下方和父控件一致,控件的右邊和父控件一致,就會(huì)導(dǎo)致控制整個(gè)變成右下

相對(duì)某個(gè)控件位置
和相對(duì)于父控件位置很相似,核心代碼都是layout_constraintBottom_toBottomOf,只是后面變成="
@+id/viewId"
如下圖,就是TextView2底部和TextView1的頭部對(duì)齊,開始位置和結(jié)束位置和父控件對(duì)其

偏移量
當(dāng)給控件增加了Top和Bottom的約束,就可以豎向產(chǎn)生偏移量,如果是增加了Start和End約束,就可以橫向的偏移量。在可視化的屬性里面,就是這里的滑動(dòng)按鈕

如果是在代碼里面,就是layout_constraintVertical_bias和layout_constraintHorizontal_bias,后面參數(shù)是百分比

控件大小
在ConstraintLayout里面,控件大小總共有三種方式
Fixed 固定大小
layout_width和layout_height 里面填寫固定的大小就可以,在可視化的屬性里面(Attributes)看到的樣子就是這樣

包裹大小 wrap_content
layout_width和layout_height 里面都是wrap_content,就是跟隨控件里面的內(nèi)容自動(dòng)變化控件大小,在可視化的屬性里面(Attributes)看到的樣子就是這樣

匹配約束 Match Constraints
就是根據(jù)空間約束的規(guī)則來分配剩余空間,有三種模式,分別是spread,percent,wrap,通過layout_constraintHeight_default和layout_constraintWidth_default字段來標(biāo)注是什么屬性,一般是spread。從可視化效果來看,就是Match Constraints,如下圖,從代碼來看就是layout-wight和layout-height都是0,自動(dòng)是Match Constraints模式。

spread 默認(rèn)
有點(diǎn)類似于match parent,不過match parent是相對(duì)于父控件,而Match Constraints是相對(duì)于約束控件來說,從可視化的屬性里面(Attributes)來看,TextView2開始和結(jié)束是相對(duì)于父控件而已,所以當(dāng)wight是Match Constraints的時(shí)候,寬會(huì)填滿整個(gè)父控件,而高雖然是相對(duì)于父控件,底部是相對(duì)于TextView1的top,當(dāng)高變成Match Constraints的時(shí)候,會(huì)占據(jù)父控件Top到TextView1的top,效果如下圖

而此時(shí),如果看代碼其實(shí)TextView2的layout-wight和layout-height都是0,就自動(dòng)是Match Constraints,而且是layout_constraintHeight_default和layout_constraintWidth_default加不加效果一樣

percent:按照父布局百分比設(shè)置
控件的尺寸是按照父控件的尺寸的百分比居中限制,需要和layout_constraintHeight_percent|layout_constraintWidth_percent配合使用,如圖,TextView是父控件就是ConstraintLayout,100%應(yīng)該是ConstraintLayout一樣大小。代碼中l(wèi)ayout_constraintHeight_percent|layout_constraintWidth_percent都是0.5,按照ConstraintLayout的50%顯示,并且居中

wrap:匹配內(nèi)容大小但是不超過約束的限制
就是能按照內(nèi)容大小去匹配,并且不能超過約束的配置,主要是對(duì)比layout_width = "wrap_content"|layout_height = "wrap_content"來的。
如下面代碼,tv1和tv2都是一樣的大小,包裹1234567789的大小,然后又給了另外一層限制,都是距離左右邊距是200dp,看tv1的效果,早就突破了這長(zhǎng)度,優(yōu)先了內(nèi)容的展示1234567789,實(shí)際上距離左右邊距沒有200dp。(tv1如果想要和tv2一樣的效果,可以通過代碼app:layout_constrainedWidth="true"|app:layout_constrainedHeight="true"設(shè)置)
而tv2,優(yōu)先保證了保持左右邊距是200dp,內(nèi)容展示不全

<androidx.constraintlayout.widget.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">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_marginStart="150dp"
android:layout_marginEnd="150dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:text="1234567789"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0" />
<TextView
android:id="@+id/tv2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="150dp"
android:layout_marginEnd="150dp"
app:layout_constraintHeight_default="wrap"
app:layout_constraintWidth_default="wrap"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintWidth_percent="0.5"
android:background="@color/colorAccent"
android:text="1234567789"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
比例寬高
app:layout_constraintDimensionRatio="1:1"|app:layout_constraintDimensionRatio="0.5"可以設(shè)置款高比例,但是需要至少款高有一個(gè)為0。兩種設(shè)置方式,1:1代表寬度和高度之間的比率,也可以用0.5等浮點(diǎn)型表示
<androidx.constraintlayout.widget.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">
<TextView
android:id="@+id/tv2"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:3"
app:layout_constraintHeight_default="wrap"
app:layout_constraintWidth_default="wrap"
android:background="@color/colorAccent"
android:text="1234567789"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果展示是

輔助線 Guidelines
自身設(shè)置
可以建立一條輔助線,將控件用于輔助線約束,可以在可視化的界面直接拖拽,通過點(diǎn)擊下面小三角來改變約束位置和位置數(shù)值

通過代碼來看,orientation控制是橫還是豎
layout_constraintGuide_begin控制位置,如果是距離開始是位置是layout_constraintGuide_begin,如果是距離結(jié)束的位置是layout_constraintGuide_end;如果是變成百分比,是layout_constraintGuide_percent="0.5"
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="206dp" />
其余控件相對(duì)位置
就是直接通過layout_constraintBottom_toBottomOf等約束,這次是textView1的結(jié)束和guideline1對(duì)齊,textView2的開始和guideline1對(duì)齊,也就是textView1和textView2分別在guideline1兩邊
<TextView
android:id="@+id/textView1"
android:layout_width="100dp"
android:layout_height="200dp"
android:background="@color/colorAccent"
android:text="TextView 1"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="@+id/guideline1"
/>
<TextView
android:id="@+id/textView2"
android:layout_width="100dp"
android:layout_height="200dp"
android:background="@color/colorPrimary"
android:text="TextView2"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline1"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />

自動(dòng)化約束
自動(dòng)連接 Autoconnect
當(dāng)開啟了Autoconnect的時(shí)候,也就是可視化頁面上面磁鐵的按鈕,一般情況下會(huì)關(guān)閉,拖動(dòng)控件到合適的位置,會(huì)自動(dòng)添加約束。

推斷約束 Infer Constraints
我們可以把控件拖到各自位置,按照想要的布局排好,然后點(diǎn)擊Infer Constraints按鈕,也就是發(fā)光棒的樣子的按鈕,會(huì)自動(dòng)推斷當(dāng)前頁面上控件布局,給所有控件添加約束

基線對(duì)齊
可以通過layout_constraintBaseline_toBaselineOf讓兩個(gè)控件幾線對(duì)齊,比如,我們又text1和text2,text2的開始位置和text1的結(jié)束位置對(duì)齊,此時(shí),我們加上layout_constraintBaseline_toBaselineOf,可以讓text1和text2的基線對(duì)齊

角度約束
可以約束某個(gè)控件相對(duì)于某個(gè)控件的角度,比如text2在text1的100dp外90°的方向。0°是正上方,順時(shí)針旋轉(zhuǎn),所以text2在text1的右邊。

代碼主要是這個(gè)三個(gè)
app:layout_constraintCircle="@id/tv1" //目標(biāo)控件的id
app:layout_constraintCircleAngle="90" //對(duì)于目標(biāo)控件的角度,負(fù)數(shù)無效
app:layout_constraintCircleRadius="100dp" //到目標(biāo)控件中間的距離
<androidx.constraintlayout.widget.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">
<TextView
android:id="@+id/tv1"
android:background="@color/colorPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text1"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv2"
android:text="Text2"
android:textSize="20sp"
android:background="@color/colorAccent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintCircle="@id/tv1"
app:layout_constraintCircleAngle="90"
app:layout_constraintCircleRadius="100dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
控件內(nèi)邊距、外邊距、GONE Margin
內(nèi)外邊距
這個(gè)和別的控件一模一樣,主要是通過layout_margin和padding來控制的
GONE Margin
這個(gè)屬性比較奇怪,當(dāng)依賴的目標(biāo)是gone的時(shí)候,本目標(biāo)的GONE Margin才會(huì)生效,而且要注意方向,比如設(shè)置了layout_constraintTop_toTopOf方向約束,那么layout_goneMarginTop才會(huì)生效
如圖,依賴的控件沒有g(shù)one的時(shí)候,goneMargin沒有效果

等控件tv1隱藏

Barrier(屏障)
這個(gè)和基線一樣,是個(gè)不顯示在屏膜上的,可以對(duì)多個(gè)控件進(jìn)行一個(gè)自動(dòng)合適的適配
比如下圖,ABC三個(gè)控件,我希望B是放在A和C的右側(cè),但是A和C里面的文字不定的,不知道哪個(gè)長(zhǎng)一點(diǎn),如果我設(shè)定B是在A的右側(cè),當(dāng)C過長(zhǎng)的時(shí)候,可能就覆蓋了B,雖然可以使用一個(gè)控件包裹AC來完成,但是多了一層,可以使用Barrier

Barrier是一個(gè)控件,控件并不顯示在頁面上, 只是為了約束別的控件,主要有兩個(gè)屬性
<!-- 用于控制Barrier相對(duì)于給定的View的位置 -->
app:barrierDirection="top|bottom|left|right|start|end"
<!-- 取值是要依賴的控件的id,Barrier將會(huì)使用ids中最大的一個(gè)的寬/高作為自己的位置 -->
app:constraint_referenced_ids="id,id"
比如如下代碼,需要依賴的控件是tvA,tvB,位于這些控件的end。會(huì)根據(jù)tvA,tvB自適應(yīng),如果tvA比較長(zhǎng),就是tvA后面,tvB比較長(zhǎng),就是tvB后面。
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
app:constraint_referenced_ids="tvA,tvC"
app:barrierDirection="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
效果圖如下

可以通過把控件B放在Barrier右側(cè)來實(shí)現(xiàn)我們要的功能

Group(組)
就是可以把控件加入一個(gè)組,對(duì)一組控件進(jìn)行顯示或者隱藏操作,同樣不顯示在頁面上,主要就是通過constraint_referenced_ids="id,id……"將控件Id添加進(jìn)去
<androidx.constraintlayout.widget.Group
android:visibility="gone"
app:constraint_referenced_ids="tvA,tvB,tvC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Placeholder(占位符)
可以在頁面上提前部署一個(gè)占位符的控件,通過調(diào)用這個(gè)占位符的setContent(int id),可以將別的控件移動(dòng)到占位符控件的位置
<androidx.constraintlayout.widget.Placeholder
android:id="@+id/place"
android:layout_width="50dp"
android:layout_height="50dp"
app:layout_constraintEnd_toEndOf="parent" />
Chains(鏈)
把一系列控件首位相連進(jìn)行排列,會(huì)自動(dòng)形成鏈,默認(rèn)是spread,均分剩余空間,有水平鏈或者垂直鏈,代碼如下
<androidx.constraintlayout.widget.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">
<TextView
android:id="@+id/tvA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="A"
android:textSize="40sp"
app:layout_constraintEnd_toStartOf="@id/tvB"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/tvB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="B"
android:textSize="40sp"
app:layout_constraintEnd_toStartOf="@id/tvC"
app:layout_constraintStart_toEndOf="@id/tvA" />
<TextView
android:id="@+id/tvC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="C"
android:textSize="40sp"
app:layout_constraintStart_toEndOf="@id/tvB"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果呈現(xiàn)就是三個(gè)控件均勻分布

layout_constraintHorizontal_chainStyle和layout_constraintVertical_chainStyle分別對(duì)水平和垂直鏈設(shè)置模式,模式可選的值有:spread、packed、spread_inside。
spread:就是默認(rèn)的均分
packed:所有控件緊貼在一起

spread_inside:兩側(cè)的控件貼近兩邊,剩下的控件均分

鏈還可以設(shè)置權(quán)重,通過layout_constraintHorizontal_weight|layout_constraintVertical_weight來設(shè)置
代碼如下
<androidx.constraintlayout.widget.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">
<TextView
android:id="@+id/tvA"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintHorizontal_chainStyle="packed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="A"
android:textSize="40sp"
app:layout_constraintEnd_toStartOf="@id/tvB"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/tvB"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintHorizontal_chainStyle="packed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:text="B"
android:textSize="40sp"
app:layout_constraintEnd_toStartOf="@id/tvC"
app:layout_constraintStart_toEndOf="@id/tvA" />
<TextView
android:id="@+id/tvC"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintHorizontal_chainStyle="packed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:text="C"
android:textSize="40sp"
app:layout_constraintStart_toEndOf="@id/tvB"
app:layout_constraintEnd_toStartOf="@id/tvD"/>
<TextView
android:id="@+id/tvD"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintHorizontal_chainStyle="packed"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:text="D"
android:textSize="40sp"
app:layout_constraintStart_toEndOf="@id/tvC"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖

Flow 流式布局
一般鏈約束需要控件首尾相連,但是可以使用Flow,會(huì)默認(rèn)將所有控件約束起來。Flow本身不展示在頁面上,也是一種虛擬布局。需要的constraintlayout 2.0才有,如果沒有,需要去build.gradle看一下constraintlayout的版本
通過app:constraint_referenced_ids="id1,id2,id3……"等設(shè)置要進(jìn)行布局的控件id
通過app:flow_wrapMode=""來設(shè)置排列方式,none是默認(rèn),就是連續(xù)排列,超出的部分不可見。chian是超出部分自動(dòng)換行,同行的會(huì)平分。aligned是超出部分自動(dòng)換行,同行會(huì)一邊靠齊。
通過orientation屬性,決定是垂直還是水平。
常規(guī)使用如下,TextView的id就是A,B,C,D,E,文本也是,通過Flow的app:constraint_referenced_ids將id添加,app:flow_wrapMode可以寫也可以不寫,默認(rèn)就是none。

排列方式:app:flow_wrapMode
none:默認(rèn)屬性,就是連續(xù)平分空間的排列,如果超出的部分則不可見,代碼如下
<androidx.constraintlayout.widget.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">
<TextView
android:id="@+id/A"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="A"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/B"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="B"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/C"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="C"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/D"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="D"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/E"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="E"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/F"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="F"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/G"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="G"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/H"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="H"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flow_wrapMode="none"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖如下

chain:超出部分自動(dòng)換行,并且所有控件等分
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flow_wrapMode="chain"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H" />
效果圖

aligned:超出部分也自動(dòng)換行,但是不是等分而是靠一邊顯示
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flow_wrapMode="aligned"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H" />
效果圖

排列方向:orientation
通過orientation為horizontal|vertical可以控制是水平還是垂直,orientation為vertical是垂直,默認(rèn)是水平
<androidx.constraintlayout.helper.widget.Flow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H" />
效果圖

間隔距離:flow_horizontalGap|flow_verticalGap
通過flow_horizontalGap|flow_verticalGap可以設(shè)置各個(gè)控件水平或者垂直的間隔距離,要注意一下是水平還是垂直方向的排列,下面代碼,是垂直排列,而且間隔是20dp,可以看到控件不在緊緊貼在一起了。
<androidx.constraintlayout.helper.widget.Flow
app:flow_verticalGap="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:constraint_referenced_ids="A,B,C,D,E,F,G,H" />
效果圖

每條鏈配置
當(dāng)flow_wrapMode的值是chian或aligned時(shí),通過flow_horizontalStyle等屬性,可以對(duì)每條鏈或者所有鏈進(jìn)行配置,有三種模式,和鏈一樣
spread:均分排列

packed:貼在一起居中

spread_inside:緊貼兩邊,其余的均分

app:flow_horizontalStyle="packed|spread|spread_inside" 所有水平鏈的配置
app:flow_verticalStyle="packed|spread|spread_inside" 所有垂直鏈的配置
app:flow_firstHorizontalStyle="packed|spread|spread_inside" 第一條水平鏈的配置,其他條不生效
app:flow_firstVerticalStyle="packed|spread|spread_inside" 第一條垂直鏈的配置,其他條不生效
app:flow_lastHorizontalStyle="packed|spread|spread_inside" 最后一條水平鏈的配置,其他條不生效
app:flow_lastVerticalStyle="packed|spread|spread_inside" 最后一條垂直鏈的配置,其他條不生效
對(duì)齊約束
控件在Flow里面,默認(rèn)是居中對(duì)齊的,但是控件大小不一樣,可以設(shè)置不同的對(duì)齊方式。通過flow_verticalAlign|flow_horizontalAlign來控制。如果是水平鏈?zhǔn)峭ㄟ^flow_verticalAlign控制,如果是垂直鏈?zhǔn)峭ㄟ^flow_horizontalAlign控制。下面都是以水平鏈做展示
top:頭部對(duì)齊
<androidx.constraintlayout.helper.widget.Flow
app:flow_horizontalGap="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:constraint_referenced_ids="A,B,C,D,E,F"
app:flow_verticalAlign="top" />

bottom:底部對(duì)齊

center:居中對(duì)齊

baseline:基線對(duì)齊
要注意一下,當(dāng)其中一個(gè)TextView里面的文字F不在中間的時(shí)候,是根據(jù)F的基線對(duì)齊的,如果是都是在中間,和center效果一樣

數(shù)量約束 flow_maxElementsWrap
可以通過flow_maxElementsWrap = "數(shù)量值"來約束一條鏈最大的數(shù)量,需要配合flow_wrapMode屬性使用,如下代碼,flow_maxElementsWrap約束了一條鏈最多4個(gè),配合了flow_wrapMode是多的靠一邊排列,如是none不行,顯示不出效果
<androidx.constraintlayout.helper.widget.Flow
app:flow_horizontalGap="10dp"
app:flow_wrapMode="aligned"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:constraint_referenced_ids="A,B,C,D,E,F"
app:flow_verticalAlign="center"
app:flow_maxElementsWrap="4"/>
效果圖

Layer層布局
本質(zhì)上而已,這個(gè)控件是把可以把別的控件加載在它上面,變成一層一層的,它沒辦法自己設(shè)置位置,設(shè)置大小,跟著它上面的層自己調(diào)整,它不是虛擬的控件,可以被看見,如果它是最上面一層,會(huì)覆蓋所有的層。主要也是通過constraint_referenced_ids添加別的層的id。
下面代碼,雖然寫了Layer的位置和大小,但是全部失效,是跟著A和B控件來的,顏色沒有失效,可以看到。Layer是在A和B前面寫的,所有在最底層,如果在A和B后面就會(huì)覆蓋掉A和B。
constraint_referenced_ids的順序沒有任何影響,Layer的順序就是寫控件的順序。
<androidx.constraintlayout.widget.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">
<androidx.constraintlayout.helper.widget.Layer
android:background="@color/colorAccent"
android:layout_width="300dp"
android:layout_height="300dp"
app:constraint_referenced_ids="A,B"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/A"
android:layout_width="60dp"
android:layout_height="90dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="A"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:id="@+id/B"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:text="B"
android:textColor="@color/colorWhite"
android:textSize="25sp"
android:textStyle="bold" />
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖

ImageFilterButton & ImageFilterView
這兩個(gè)控件有點(diǎn)像ImageButton和ImageView的關(guān)系,有兩個(gè)特殊作用,再ImageFilterButton|ImageFilterView中都可以。下面主要用ImageFilterView測(cè)試
圓角
可以通過app:roundPercent設(shè)置圓角的比例,app:round設(shè)置大小
<androidx.constraintlayout.widget.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">
<androidx.constraintlayout.utils.widget.ImageFilterView
app:roundPercent="0.5"
app:round="50dp"
android:background="@color/colorAccent"
android:layout_width="100dp"
android:layout_height="100dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果圖

多層圖片
src可以設(shè)置第一層圖片,altSrc可以再設(shè)置一層圖片,再src上面,默認(rèn)是透明的,需要通過crossfade屬性來設(shè)置,0-1直接的值
效果圖如下,第一層圖片是Android的圖標(biāo),第二層圖片破了的圖片,crossfade是0.5

其余屬性調(diào)整
warmth屬性可以用來調(diào)節(jié)色溫
brightness屬性用來調(diào)節(jié)亮度
saturation屬性用來調(diào)節(jié)飽和度
contrast屬性用來調(diào)節(jié)對(duì)比度
這幾個(gè)屬性涉及到美術(shù)了,目前不太了解
MockView 原型圖軟件
這個(gè)控件,說可以來畫原型圖,id就是控件里面的文字,使用很簡(jiǎn)單
<androidx.constraintlayout.utils.widget.MockView
android:id="@+id/MockView"
android:layout_width="100dp"
android:layout_height="100dp"/>
效果如下
