說點(diǎn)大家的觀點(diǎn)掷贾,有點(diǎn)啰嗦
1睛榄、ConstraintLayout
允許通過無嵌套視圖方式創(chuàng)建大型而復(fù)雜的布局。類似于RelativeLayout
想帅,所有視圖均根據(jù)同級(jí)視圖和父級(jí)布局之間的關(guān)系進(jìn)行布局场靴,但是它比RelativeLayout更靈活,更易于使用博脑。
當(dāng)然憎乙,這里有人是有不同意見的,所有控件都是同一個(gè)父View叉趣,會(huì)顯得比較散,分模塊操作時(shí)效率較低该押。畢竟就目前來說疗杉,也就只有Group來控制一組控件的顯示與否。
2.0
之后添加的Layer
會(huì)改善這種情況蚕礼。
而且就正常情況下烟具,在ConstaintLayout里面添加一些其它ViewGroup有時(shí)也是無可避免的嘛
2、Android Studio 同時(shí)還提供特有的布局編輯器奠蹬,ConstraintLayout的布局內(nèi)容均可以通過拖拉拽(以及編輯器的右邊屬性欄)達(dá)成朝聋。
不過現(xiàn)在階段,慣性思維下囤躁,對(duì)于拖拉拽的不習(xí)慣以至于大多人還在觀望冀痕,即便使用上了荔睹,也會(huì)習(xí)慣性的使用編寫XML的方式!
當(dāng)然有時(shí)候只需要修改一行或幾行屬性言蛇,手寫會(huì)來得快僻他。
哦對(duì)了,喜歡手寫的直接在編輯器的右邊屬性欄一個(gè)個(gè)添加約束腊尚,也未嘗不可吨拗。
另外2.0的基于ConstaintLayout的MotionLayout
據(jù)說是特強(qiáng)大的動(dòng)畫布局,Android Studio 4.0 版本也提供了拖拉拽來實(shí)現(xiàn)婿斥,到時(shí)候動(dòng)畫可能就看你的想象力了劝篷。
3、畢竟Google對(duì)于約束布局的支持是很大的民宿,ConstaintLayout之于RelativeLayout娇妓,就像RecycleView之于ListView,終究強(qiáng)者是要上位的勘高。大勢所趨峡蟋!大家都在學(xué),你不學(xué)华望,落后就要挨打咯蕊蝗。
都9102年了,別裝睡了赖舟,你還能學(xué)蓬戚。
共勉。
使用方式
1. 導(dǎo)入包:
dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
// androidx:
// implementation "androidx.constraintlayout:constraintlayout:1.1.3"
}
目前最新版本是1.1.3宾抓。 2.0版本已經(jīng)在測試中了子漩,等到2.0,新的特性就更多了石洗!
什么Layer幢泼、Flow、MotionLayout等讲衫。
基礎(chǔ)使用
2. 相對(duì)定位
定義一個(gè)控件的位置缕棵,起碼要使其在縱橫方向各至少擁有一個(gè)相對(duì)約束---即相對(duì)于其它控件的位置∩媸蓿看下面這個(gè)圖
布局編輯器顯示控件 C 在 A下面, 但是 C并沒有設(shè)置垂直方向的約束招驴,運(yùn)行時(shí)會(huì)默認(rèn)在父布局的頂端,與我們所預(yù)想的發(fā)生偏差枷畏。
相對(duì)約束的基本屬性格式是
layout_constraintDirection1_toDirection2Of
Direction1和Direction2可以是Left别厘、Top、Right拥诡、Bottom
其中任意的左右
或者上下
的組合触趴,也可以是Start氮发、End
組合(根據(jù)從左向右布局,Start == Left雕蔽,End == Right)折柠。后續(xù)出現(xiàn)的Direction均代表這個(gè)屬性。
從屬性名我們就可直譯出其代表的意思批狐,比如:
layout_constraintTop_toBottomOf="@id/btn1"扇售,約束該控件的上邊界在btn1的下邊界下面,且若不設(shè)置邊距(margin)嚣艇,則與btn1下邊界在同一水平線上承冰。
<?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/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:text="button1"/>
<Button
android:id="@+id/btn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn1"
app:layout_constraintLeft_toRightOf="@id/btn1"
android:text="button2"/>
</android.support.constraint.ConstraintLayout>
那么例子中btn2的相對(duì)約束就是在btn1的右下角。(btn1中的parent表示相對(duì)父布局的位置)
當(dāng)然還有一種常用的文字基線對(duì)齊食零,屬于垂直方向的約束,與RelativeLayout的alignBaseLine屬性相似
layout_constraintBaseline_toBaselineOf
3. Margin
用于設(shè)置與其它控件的邊距困乒。
與其它Layout類型不同的是,Margin的設(shè)置依賴于控件是否有添加相應(yīng)方向的相對(duì)約束贰谣。
當(dāng)設(shè)置了某個(gè)方向的邊界的相對(duì)約束之后娜搂,該方向設(shè)置的margin才能生效!
否則margin無效吱抚。
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="20dp"
android:text="button1"/>
上述android:layout_marginRight="20dp"
無效百宇。當(dāng)然如果你通過布局編輯器操作的話,本身就無法寫入這一條無效語句秘豹,如果你用的是xml寫入的這一條携御,然后再去編輯器編輯該控件的時(shí)候,會(huì)發(fā)現(xiàn)這條語句也會(huì)被優(yōu)化而刪除既绕!
特殊情況:設(shè)置了Margin的控件的visibility屬性變?yōu)閂iew.Gone
- View.Gone 的控件在約束布局中啄刹,依然可以通過findViewById()找到,只是寬高都為0dp凄贩,即視為一個(gè)點(diǎn)誓军,且其每個(gè)方向的margin也都變?yōu)?
- 由于View A 已經(jīng)Gone,則其他依賴于View A的疲扎,如View B的位置會(huì)有相應(yīng)的變化谭企,防止出現(xiàn)顯示異常,View B通過可以設(shè)置
layout_goneMarginDireaction
來設(shè)置當(dāng)View A Gone時(shí)候的間距评肆。如
app:layout_goneMarginLeft="20dp"
4.圓形定位
相較于相對(duì)定位,圓形定位的屬性就很簡單了非区,只有如下三個(gè)約束
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />
解讀下就是:以ButtonA的中心點(diǎn)作為原點(diǎn)瓜挽,從原點(diǎn)處以Y軸正半軸向右偏離45度畫一條長度為100dp的線段,線段的另一個(gè)頂點(diǎn)為ButtonB的中心點(diǎn)征绸!
值得注意的是久橙,圓形定位優(yōu)先于相對(duì)定位俄占。
Android Studio 當(dāng)前版本(3.5)并沒有直接支持拖拽來寫這些角度。淆衷。不寫相對(duì)約束居然還飄紅缸榄,有點(diǎn)過分
5. 居中與傾向(Biaz)
這個(gè)就有點(diǎn)意思
<!--水平方向添加左右兩條約束-->
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/btn1"
app:layout_constraintEnd_toStartOf="@+id/btn2"
/>
當(dāng)控件在水平(或垂直)方向左右(上下)同時(shí)使用了相對(duì)約束,那么控件會(huì)位于兩個(gè)約束控件的正中間。
比如說上述代碼祝拯,tv1的約束條件是甚带,在btn1的右邊,btn2的左邊佳头,按照規(guī)定鹰贵,三個(gè)控件在水平線上應(yīng)該是緊緊相鄰的,但是這里不可能做到,除非tv1的寬度剛好等于btn1與btn2的間距康嘉。
所以在這種約束規(guī)則下碉输,tv1的表現(xiàn)為位于btn1和btn2的正中間。
當(dāng)然有時(shí)候需要的不僅是居中而是中間偏左亭珍,或者偏上之類的敷钾。
那么要需要設(shè)置:
//居中默認(rèn)為 0.5,取值0.0-1.0
//小于0.5即偏左(也不一定肄梨,就比如上述例子阻荒,若btn2與btn1間距小于tv的寬度
//那么小于0.5就偏右了)
app:layout_constraintHorizontal_bias = "0.5"
//垂直方向同理
app:layout_constraintVertical_bias = "0.5"
另外1,在此規(guī)則下峭范,若將相對(duì)應(yīng)的寬高設(shè)置為0dp财松,則控件會(huì)撐滿間距!同時(shí)bias設(shè)置無效纱控。
另外2辆毡,上述這個(gè)例子中,根據(jù)tv1的約束甜害,若btn2在btn1的左邊會(huì)發(fā)生什么呢舶掖?
實(shí)際上tv1的中心點(diǎn)依然會(huì)在這btn1和btn2的兩條約束邊界的中間,此時(shí)設(shè)置bias小于0.5時(shí)tv1會(huì)偏右尔店。
6.寬高比
作為ConstraintLayout的子控件眨攘,其寬高一般是不支持設(shè)置為match_parent的,而是使用match_constraint
代替(xml中使用0dp表示match_constraint)嚣州。之所以是“一般不支持”鲫售,控件有在比較簡單約束條件下,match_parent是和0dp等效的该肴,所以還是用0dp就可以了情竹。
使用match_constraint的控件最好同時(shí)有設(shè)置其左右
/上下
的約束組合!否則匀哄,有可能會(huì)真的是0dp秦效。
進(jìn)入正題雏蛮,當(dāng)有寬高至少有一邊設(shè)置為0dp時(shí),我們可以設(shè)置該控件的寬高比阱州!
- 當(dāng)只有一邊設(shè)置為0dp:
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintDimensionRatio="1:2"
// 默認(rèn)格式為挑秉,寬:高,可通過添加W或H來改變苔货,如 "H,1:2" 為高:寬 = 2:1
此時(shí)"1:2" == "W,1:2" == "H,2:1"犀概, W/H 用于指定分子與分母
該控件寬高比會(huì)變?yōu)?:2,由于layout_width="0dp"蒲赂,則寬度隨著高度變化而變化阱冶。
- 如若寬高都為0dp。
在這種情況下滥嘴,系統(tǒng)將設(shè)置滿足所有約束并維持指定長寬比的最大尺寸木蹬。
(這句話翻譯自文檔,要細(xì)品若皱。)
假設(shè)控件A在水平的左右方向都存在約束镊叁,垂直方向只有一條約束。相對(duì)于垂直方向走触,A在水平方向上的寬度比較固定(等于屏幕寬度)晦譬,所以高度會(huì)根據(jù)比例跟著變化。
假設(shè)控件A在水平方向以及垂直方向都有存在約束互广,那就可以通添加w或h來指定約束方向敛腌。
app:layout_constraintDimensionRatio="w,1:2" //或 "h,1:2"
"w,1:2"表示 寬度根據(jù)高度變化而變化,且寬高比依舊是1:2
"h,1:2"表示 高度根據(jù)寬度變化而變化惫皱,且寬高比依舊是1:2
W/H 是用于指定約束方向
7.尺寸約束
定義layout_width和layout_height的時(shí)候像樊,同樣是有三種方式:固定值、wrap_content旅敷、0dp
- 使用 wrap_content的時(shí)候生棍,可以使用如下來限制控件大小
android:minWidth 設(shè)置布局的最小寬度
android:minHeight 設(shè)置布局的最小高度
android:maxWidth 設(shè)置布局的最大寬度
android:maxHeight 設(shè)置布局的最大高度
- 使用0dp時(shí)則可以使用:
layout_constraintWidth_min、layout_constraintHeight_min:將為此控件設(shè)置最小尺寸
layout_constraintWidth_max媳谁、layout_constraintHeight_max:將為此控件設(shè)置最大尺寸
layout_constraintWidth_percent涂滴、layout_constraintHeight_percent:將此控件的尺寸設(shè)置為父控件的百分比
輔助工具類
終于到了重中之重了,這些拓展的輔助工具類才是ConstaintLayout真香于RelativeLayout的地方晴音。
8. Chain
鏈雖然沒有一個(gè)具體的類柔纵,比如Chain.java,但是也算一種特殊的約束锤躁,就也歸入輔助工具類吧首量。在2.0版本將見到更強(qiáng)大的Flow輔助類。
鏈,兩個(gè)及以上的控件兩兩相互約束加缘。且頭尾兩邊的控件受約束于同一水平軸的其他非此鏈成員控件(比如parent),鏈才能正常生效觉啊。約束效果如下圖
通過鏈頭(最靠左邊或上邊的控件)設(shè)置如下屬性來達(dá)到不同分布效果
//layout_constraintHorizontal_chainStyle
layout_constraintVertical_chainStyle = "spread_inside|spread|packed"
下述便于解說拣宏,就圖上的例子,鏈兩邊控件(A和C)的約束控件為父控件parent
- Spread
默認(rèn)的類型杠人,在充分考慮了margin之后勋乾,鏈上的控件均勻分布(在考慮margin之后的,布局剩余的空間嗡善,均勻分配給在各個(gè)控件的間隙辑莫,包括與parent的間隙。若剩余空間為負(fù)值,即控件總長度大于父控件兩邊界的間距罩引,則間隙為0各吨,此時(shí)鏈居中,兩邊超出屏幕外的控件自生自滅)
- Spread inside
A和C控件固定在鏈的兩端的約束上袁铐,即貼著parent揭蜒,其余控件均勻分布。
相對(duì)于Spread布局剔桨,不同的是屉更,布局剩余的空間不考慮兩邊控件與parent的間隙。當(dāng)然若是空隙為負(fù)洒缀,表現(xiàn)則同Spread模式
- Weighted
加權(quán)分布瑰谜,在上述這兩種模式中,若有一控件將寬度設(shè)置為0dp树绩,那么該控件將充滿剩余的空間萨脑。而且,類似于LinearLayout,對(duì)于剩余的空間可以通過設(shè)置每個(gè)控件的權(quán)重屬性:
app:layout_constraintHorizontal_weight = 1
//app:layout_constraintVertical_weight = 1
根據(jù)權(quán)重為不同的控件分配不同比例的空間葱峡。
- Packed
將每個(gè)控件緊貼(需要考慮margin)在一起砚哗,剩余的空間間隙分配在兩邊控件與parent之間。而且可以通過調(diào)節(jié)鏈頭的bias來分配兩邊間隙砰奕。
若間隙小于0蛛芥,表現(xiàn)如同Spread。
另外生成鏈的時(shí)候军援,記得使用下面這種簡便形式仅淑!不然一個(gè)一個(gè)控件去添加約束,累死個(gè)人了胸哥。
9. Guideline
指導(dǎo)線涯竟,作為其它控件的約束準(zhǔn)則。其它控件可以方便的通過GuideLine進(jìn)行定位。
GuideLine繼承于View庐船,但并不會(huì)在布局中呈現(xiàn)(View.Gone)
可以通過設(shè)置下面三種屬性之一來設(shè)置GuideLine的位置
app:layout_constraintGuide_begin="100dp" //與parent左邊界或上邊界(根據(jù)GuideLine的方向)的距離
app:layout_constraintGuide_end="100dp" ////與parent右邊界或下邊界(根據(jù)GuideLine的方向)的距離
app:layout_constraintGuide_percent="0.5" // 百分比, 0~1
android:orientation="vertical|horizontal" //設(shè)置方向
10. Barrier
柵欄银酬,類似于GuideLine,設(shè)置為View.GONE,也是設(shè)置輔助線的作用筐钟,不過這個(gè)輔助線取決于多個(gè)控件的同一側(cè)邊界揩瞪。當(dāng)所依賴的控件大小有所變化的時(shí)候,Barrier也有可能跟著變化篓冲。
假設(shè)Barrier定義如下:
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right" // 或left李破、top、bottom
app:constraint_referenced_ids="buttonA,buttonB" //引用多個(gè)控價(jià)壹将,用逗號(hào)隔開
/>
<Button
android:id="@+id/buttonC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintStart_toEndOf="@+id/barrier"
app:layout_constraintTop_toTopOf="parent"
/>
即Barrier的位置取決于buttonA和buttonB誰的右邊界更靠右嗤攻,而ButtonC在Barrier的右邊。
這里還有個(gè)知識(shí)點(diǎn):Barrier 繼承于 ConstraintHelper
诽俯,而ConstraintHelper繼承于View.
ConstraintHelper是用于管理一組控件的行為妇菱,與ViewGroup不同的是:1.不增加層級(jí);2. 不同的Helper可以引用同一個(gè)控件
在2.0版本支持自定義Helper惊畏。
11. Group
這個(gè)比較簡單了恶耽,也是繼承于ConstraintHelper, 用于控制一組控件的顯示與否。
<androidx.constraintlayout.widget.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
app:constraint_referenced_ids="button1,button2" />
值得注意的是颜启,由于控件被包含在Group中偷俭,通過 View.setVisibility(int)來控制控件的顯示與否,是無效的缰盏。
另外涌萤,當(dāng)一個(gè)控件被添加在不同的Group中,此時(shí)這根據(jù)布局文件中排最后一個(gè)的Group將具有一票否決權(quán)口猜。
12. PlaceHolder
占位是指提前設(shè)置一個(gè)繪制內(nèi)容為空的控件负溪,根據(jù)約束完成定位后,在恰當(dāng)?shù)臅r(shí)候?qū)⑦@個(gè)PlaceHolder的位置提供給其它控件使用济炎!
設(shè)置占位并綁定指定的控件的方式有兩種:
<android.support.constraint.Placeholder
android:id="@+id/pl"
android:layout_width="50dp"
android:layout_height="50dp"
app:content="@id/btn1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
或者
placeHolder.setContentId(R.id.btn1)
當(dāng)一個(gè)控件A被綁定至PlaceHolder川抡,有如下反應(yīng)。
- A在原位置上會(huì)被當(dāng)做View.Gone. 其它依賴于A的控件會(huì)把A當(dāng)做一個(gè)點(diǎn)來處理须尚。
- PlaceHolder的其它約束條件不變崖堤,寬高變成了A的寬高
- 在PlaceHolder的位置顯示出A的內(nèi)容
雖然目前這個(gè)功能對(duì)我來說很雞肋,但對(duì)這個(gè)功能實(shí)現(xiàn)感興趣耐床,所以我覺得這個(gè)可以稍微了解更深點(diǎn)的
在源碼中我們看到這幾處代碼:
PlaceHolder.class
//根據(jù)綁定的控件密幔,更新PlaceHolder測量后的寬高
public void updatePostMeasure(ConstraintLayout container) {
if (this.mContent != null) {
LayoutParams layoutParams = (LayoutParams)this.getLayoutParams();
LayoutParams layoutParamsContent = (LayoutParams)this.mContent.getLayoutParams();
layoutParamsContent.widget.setVisibility(0);
// 這里
layoutParams.widget.setWidth(layoutParamsContent.widget.getWidth());
layoutParams.widget.setHeight(layoutParamsContent.widget.getHeight());
layoutParamsContent.widget.setVisibility(8); //控件不可見
}
}
//PlaceHolder.class
// 在layout()之前將綁定的控件 layoutParamsContent.isInPlaceholder = true
public void updatePreLayout(ConstraintLayout container) {
if (this.mContentId == -1 && !this.isInEditMode()) {
this.setVisibility(this.mEmptyVisibility);
}
this.mContent = container.findViewById(this.mContentId);
if (this.mContent != null) {
LayoutParams layoutParamsContent = (LayoutParams)this.mContent.getLayoutParams();
layoutParamsContent.isInPlaceholder = true; //這個(gè)屬性
this.mContent.setVisibility(0);
this.setVisibility(0);
}
}
ConstraintLayout.class
// 更新綁定的控件的位置
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int widgetsCount = this.getChildCount();
boolean isInEditMode = this.isInEditMode();
int helperCount;
for(helperCount = 0; helperCount < widgetsCount; ++helperCount) {
View child = this.getChildAt(helperCount);
...
if (child instanceof Placeholder) {
Placeholder holder = (Placeholder)child;
View content = holder.getContent();
if (content != null) {
content.setVisibility(0);
content.layout(l, t, r, b); //更改所綁定控件的顯示位置
}
}
}
}
...
}
用文字來描述就是,當(dāng)一個(gè)控件A被添加到PlaceHolder后撩轰,會(huì)被標(biāo)記為isInPlaceholder=true
,且A被設(shè)置為View.Gone, 那么其它依賴于A的控件就會(huì)把A當(dāng)成一個(gè)點(diǎn)胯甩。
同時(shí)在測量完成后(layout之前)昧廷,將PlaceHolder的寬高修改為A的寬高
接著在onLayout過程時(shí),A設(shè)為View.VISIABLE, PlaceHolder的布局位置讓給A偎箫,即執(zhí)行A.layout(l,t,r,b)(參數(shù)來自PlaceHolder)
此時(shí)雖然A可見了木柬,但依賴于A的其它控件的大小及位置已經(jīng)與A無關(guān)了。(這里沒深究镜廉,大小是因?yàn)榕澹瑴y量時(shí)因?yàn)锳為Gone,布局位置應(yīng)當(dāng)是與A.layoutParams.isInPlaceholder == true
相關(guān))
Optimizer
優(yōu)化器娇唯,系統(tǒng)會(huì)自動(dòng)嘗試減少視圖的約束,從而提高布局速度
官方還沒啥使用文檔寂玲。塔插。
給出了這么個(gè)使用方式:
添加:app:layout_optimizationLevel 到 ConstraintLayout的標(biāo)簽中
app:layout_optimizationLevel="direct|barrier|chain"
這個(gè)屬性值有六種,standard為默認(rèn)形式拓哟,即會(huì)優(yōu)化direct和barrier這兩種類型的約束
none : no optimizations are applied // 不優(yōu)化
standard : Default. Optimize direct and barrier constraints only
direct : optimize direct constraints
barrier : optimize barrier constraints
chain : optimize chain constraints (experimental) // 實(shí)驗(yàn)性
dimensions : optimize dimensions measures (experimental), reducing the number of measures of match constraints elements // 實(shí)驗(yàn)性
關(guān)于這個(gè)幾個(gè)屬性,在這個(gè)問答中有比較詳細(xì)的解釋。大家自己看看吧气堕。
https://stackoverflow.com/questions/49802490/what-is-constraintlayout-optimizer
猜測:上文設(shè)置無效margin約束拆挥,會(huì)自動(dòng)被優(yōu)化刪除,可能就是這個(gè)觸發(fā)的违诗?
ConstrainsSet 與 ConstaintLayout.LayoutParams
ConstaintLayout.LayoutParams
顧名思義漱凝,就是我們布局參數(shù)了。
通常我們可以通過修改布局參數(shù)值來控制一個(gè)控件的呈現(xiàn)形式诸迟。
但是ConstaintLayout的特殊性茸炒,如果要做一些比較復(fù)雜的變更步驟就會(huì)變得繁瑣,比如說在Chain中加入一個(gè)控件阵苇,你覺得還行壁公?那將幾個(gè)控件組成一條鏈呢?
所以谷歌的建議是绅项,使用ConstrainsSet
來進(jìn)行動(dòng)態(tài)修改控件的參數(shù)紊册。ConstrainsSet.createHorizontalChain(...) 就可以創(chuàng)建一條鏈,不過這里更多是需要理解方法中的參數(shù)
接著了解下使用方式:
- 生成ConstaintSet對(duì)象快耿。
無參對(duì)象
val c = new ConstraintSet();
從已存在的layout中導(dǎo)出所有子控件的約束形成約束集
c.clone(context, R.layout.layout1);
c.clone(cLayout);
- 修改指定的控件的約束條件
c.setAlpha(int viewId, float alpha)
c.constrainHeight(int viewId, int height)
//設(shè)置控件間的相對(duì)約束囊陡,side的取值為1~7
//即:ConstaintSet.LEFT、ConstaintSet.RIGHT... 等上述相對(duì)布局可使用的7個(gè)Dreaction
c.connect(int startID, int startSide, int endID, int endSide)
...
//基本可通過xml設(shè)置的屬性润努,在ConstraintSet中都能找相對(duì)應(yīng)的方法
- 使步驟2中的修改生效
c.applyTo(cLayout);
// cLayout的所有控件必須都設(shè)置有viewId关斜,因?yàn)樵摲椒ㄓ腥缦屡袛啵?
if (id == -1) {
throw new RuntimeException("All children of ConstraintLayout must have ids to use ConstraintSet");
}
// 不過我注意到2.0版本是這樣的,可以通過setForceId(boolean b) 來控制是否都需要設(shè)置id
if (this.mForceId && id == -1) {
throw new RuntimeException("All children of ConstraintLayout must have ids to use ConstraintSet");
}
這里有個(gè)關(guān)鍵地方需要提下:
- 若在第一步ConstraintSet使用的是無參數(shù)的構(gòu)造方法
val set = ConstraintSet()
set.setMargin(R.id.btn1, ConstraintSet.LEFT, 300)
set.constrainWidth(R.id.btn1, 300)
set.applyTo(cLayout)
那么在setMargin()時(shí)會(huì)生成一個(gè)Constraints
對(duì)象用來存R.id.btn1的這條Margin約束。(ConstraintSet使用Map關(guān)聯(lián)viewId和Constraints)
在appleTo(cLayout)的時(shí)候上述的Constraints
替換cLayout中的R.id.btn1原本定義在xml的所有約束條件铺浇!
另外還有個(gè)可能就是痢畜,cLayout不存在id為R.id.btn1的子控件。那一般就什么都不會(huì)發(fā)生。
從源碼來看丁稀,對(duì)于這個(gè)cLayout中不存在的id吼拥,若我們使用了這樣的代碼。线衫。
val set = ConstraintSet()
set.createBarrier(R.id.btn1, ...)
set.applyTo(cLayout)
那么btn1會(huì)被作為一個(gè)新的Barrier控件加入cLayout中(addView()的方式)凿可,同理的還有GuideLine。
本文最重要的點(diǎn)
- 實(shí)踐出真章授账。多實(shí)戰(zhàn)枯跑,你會(huì)發(fā)現(xiàn)還挺好用的,然后發(fā)現(xiàn)文中一些錯(cuò)誤的主觀觀點(diǎn)...
- 參考自官方文檔:
https://developer.android.com/reference/android/support/constraint/ConstraintLayout