ConstraintLayout相關(guān)屬性用法理解及入門

前言:ConstraintLayout作為google欽定的代替LinearLayout及RelativeLayout的布局值得我們學(xué)習(xí)文兑,并且google仍舊想借此布局繼續(xù)改善之前布局可視化編輯上的雞肋效果箕般,但由于當(dāng)下版本新的可視化效果在布局編輯器上與實際運(yùn)行結(jié)果仍舊可能略有不同猪瞬,我們還是很難在不編輯代碼的情況下僅靠拖拽來編輯布局籽御,所以本文不會從拖拽入手话浇,而是從布局各種相關(guān)API的代碼層面學(xué)習(xí)該布局的使用

對于ConstraintLayout來講增蹭,為了更好的在實際應(yīng)用過程中使用它杆逗,有許多重要的概念及規(guī)則需要了解熟記,通過本文剪个,你不僅能看到ConstraintLayout官方說明的譯文秧骑,還將通過多個事例來模擬實際使用中容易遇見的問題,希望以拋磚引玉的方式引出實際應(yīng)用中可能遇到的坑扣囊,并加以避免

1.layout_constraintA_toBOf

1.1基礎(chǔ)概念



這里的AB的取值分別為下圖的top乎折、left、right等侵歇,并有形如top-bottom骂澄、start-end的對應(yīng)關(guān)系,并且這種對應(yīng)關(guān)系是必然的惕虑,下面我們會說明原因



例如:

app:layout_constraintTop_toBottomOf="@+id/"

所表達(dá)的意思為令控件Atop邊與控件Bbottom邊共享同一塊相同的位置(share the same location)

代碼運(yùn)行結(jié)果為:



所以我們就能理解不可能出現(xiàn)layout_constraintTop_toLeftOf這樣的API坟冲,因為一個是豎邊磨镶,一個是橫邊,不可能共享同一塊位置

其他的API以此類推很好理解健提,那baseline的運(yùn)行結(jié)果會是如何琳猫?為了對比,我們先看如下代碼的運(yùn)行結(jié)果:


我們令B在A的右邊矩桂,然后設(shè)置B的寬高與字體大小大于A沸移,運(yùn)行結(jié)果如我們所預(yù)想:


然后我們設(shè)置:

app:layout_constraintBaseline_toBaselineOf="@+id/tv_a"

運(yùn)行結(jié)果會不會如我們所想呢:


觀察結(jié)果可知,由于B的高度大于A侄榴,所以B上面的一部分移動到了屏幕之外,并且由于B字體大小大于A网沾,所以即便是指定BaseLine在同一位置癞蚕,B的文字也要高于A

我們再修改代碼,為父布局加入paddingTop辉哥,看能否使被屏幕遮蓋的布局“移下來”:


觀察結(jié)果:


B移到了父布局的外部桦山,在父布局上加入padding會導(dǎo)致子布局的內(nèi)容整體下移,這與我們在其他布局中的經(jīng)驗是一致的醋旦,既然這樣的話恒水,若我們直接在A上設(shè)置marginTop能否讓A“帶著”B一起下來呢,我們繼續(xù)修改代碼:


運(yùn)行結(jié)果:


觀察結(jié)果我們發(fā)現(xiàn)A并沒有按照預(yù)想挪下來饲齐,究其原因是由于我們沒有為A布局設(shè)置約束(Constraint)钉凌,所以A不知道該如何偏移,我們?yōu)锳添加約束捂人,并將A的約束對象設(shè)置為父元素ConstraintLayout本身:


觀察代碼運(yùn)行結(jié)果:


綜上御雕,約束布局中,若期望設(shè)置某控件的margin來控制顯示位置滥搭,則必須指定該控件在該方向上的約束



官方解釋為如果設(shè)置控件的margin酸纲,它會施加在存在的對應(yīng)約束上(If side margins are set, they will be applied to the corresponding constraints (if they exist))

1.2居中

查找發(fā)現(xiàn)API沒有為我們提供例如layoutGravity或centerInParent之類的方法讓我們把一個控件在約束布局內(nèi)居中,但是可以通過官方提供的方式來達(dá)到目的


指定讓控件的寬高與父布局重疊并不會令該控件鋪滿父布局瑟匆,除非父布局與控件擁有完全相同的大小闽坡,不然只會令控件在指定的方向上居中


當(dāng)控件布局成這種狀態(tài)下時,我們可以通過設(shè)置偏移(bias)來改變控件的默認(rèn)(50%)位置:



1.3由居中寫法引申而來的問題

有了以上的基礎(chǔ)概念愁溜,我們來分析幾個典型的例子疾嗅,在進(jìn)一步理解的同時也能發(fā)現(xiàn)其中的一些問題

1.3.1

上面居中代碼中,我們將A的左右邊與父布局的左右邊設(shè)定約束祝谚,最終的結(jié)果為A居中于父布局宪迟,若我們將A的右邊與B的右邊設(shè)定約束,效果會如何呢:


運(yùn)行結(jié)果:


可見A被從父布局的左邊“推離”了交惯,而在與B大小相等的位置“居中”次泽,此時我們便能隱約開始理解網(wǎng)上一些其他教程在翻譯官方說明時對于原文(What happens in this case is that the constraints act like opposite forces pulling the widget apart equally)的譯文的含義了穿仪。

1.3.2

假設(shè)我們有如下代碼:


我們將A的左邊與父容器的左邊設(shè)定約束,然后將A的右邊與B的左邊設(shè)定約束意荤,此時A既約束于父容器也約束于B容器啊片,然后將B的右邊與A的左邊相約束戒傻,然后設(shè)置A的左右margin為20dip瓦戚,設(shè)置B在4個方向上的margin也為20dp,運(yùn)行結(jié)果為:


我們發(fā)現(xiàn)A與B之間的位置關(guān)系是正確的纬凤,B控件只有左間距捐寥,這也是正確的笤昨,符合我們上面得出的間距只在約束方向上有效的結(jié)論,但是A控件的左右間距都失效了握恳,感覺有點奇怪有問題瞒窒,但此處其實我們是創(chuàng)建了一種特殊的約束布局結(jié)構(gòu)--鏈(chain),對于鏈的定義乡洼、介紹以及為何margin感覺失效的問題我們下面會詳細(xì)說明崇裁,此處先有個印象。但如果我們此時去掉B相對于A的約束束昵,僅依靠A相對于B的約束能否保持這個位置不變呢拔稳,為了方便觀察結(jié)果,我們將A與B在布局文件中書寫的順序互換:


運(yùn)行結(jié)果為:


可見锹雏,A控件在嘗試以一個詭異的位置“居中”巴比,并且B的位置并沒有依照所想能在A的右邊,究其原理逼侦,必然是約束布局內(nèi)部的計算方法導(dǎo)致其在此類情況下計算出可居中的寬度及位置并嘗試居中匿辩,具體的算法還有待翻看源碼后總結(jié),此處暫時存疑并有待補(bǔ)充榛丢,接下來我們修改間距大胁颉:


觀察結(jié)果:


我們可以確認(rèn)一點,在這種情況下晰赞,對A布局設(shè)置的margin是有效的稼病,但前提是我們沒有將A與B相互約束。

2.約束對象可見度為GONE的情況:

約束布局中掖鱼,我們可以通過設(shè)置:

layout_goneMarginX

屬性然走,來設(shè)置約束的控件對象可見度為GONE的情況下的margin數(shù)值


具體用法非常好理解,我們不再贅述戏挡。但值得注意的是芍瑞,約束布局下被設(shè)置為GONE的元素依舊是布局的一部分,與其他布局的區(qū)別在于其尺寸變?yōu)榱?褐墅,而不是脫離布局

3.約束布局內(nèi)子控件的寬高設(shè)置

官方說明常用方式為:

a.設(shè)置具體的寬高數(shù)值

b.設(shè)置寬高為wrap_content

c.設(shè)置寬高為0dp拆檬,以代表MATCH_CONSTRAINT

對于c方式洪己,約束布局中不能直接使用match_parent來設(shè)置控件的寬高,直接設(shè)置后IDE會自動轉(zhuǎn)換成0dp竟贯,這里我們有必要舉個例子與上面的居中例子做對比來說明0dp如何MATCH_CONSTRAINT


觀察結(jié)果:


C控件并沒有如我們所想match答捕,我們修改C的屬性:


運(yùn)行效果:


我們再思考一個例子,假設(shè)我們在此基礎(chǔ)上再加入一個控件D屑那,我們希望此控件位于A的正下方拱镐,并且寬度與A相同,我們寫下了如下的代碼:


運(yùn)行效果:


發(fā)現(xiàn)D在指定的兩條邊中間居中持际,符合我們上面的測試結(jié)果沃琅,現(xiàn)在我需要令D的寬與A一致,修改代碼:


運(yùn)行結(jié)果:


可以發(fā)現(xiàn)选酗,0dp指的是MATCH_CONSTRAINT阵难,而不是match_parent,需重點理解

d.設(shè)置ratio屬性

通過使用:

app:layout_constraintDimensionRatio="X,A:B"

屬性芒填,可以用比例的形式更靈活的指定控件的寬高,意思為系統(tǒng)會以最大的尺寸為依據(jù)空繁,加之寬高比殿衰,計算得出0dp所對應(yīng)的數(shù)值,其中X指的是要約束的邊盛泡,取值為W或H 且可以不填闷祥,AB為具體的比例數(shù)值,代表寬:高傲诵,我們繼續(xù)修改控件D的屬性以具體查看:


我們設(shè)置D的寬為0dp凯砍,以告知系統(tǒng)寬需要計算得出,高設(shè)置為wrap_content拴竹,然后設(shè)置ratio的值為16:9悟衩,運(yùn)行結(jié)果:


控件D以最大尺寸的邊 高為基準(zhǔn),加之以寬高比16:9共同計算出寬度栓拜,我們繼續(xù)修改代碼:


控件D的寬高均置為0dp座泳,代表均需計算得出,然后指定寬高比為16:9幕与,此時系統(tǒng)會設(shè)置最大尺寸以滿足所有約束并保證寬高比:


在此基礎(chǔ)上挑势,我們?yōu)閞atio添加要約束的邊,


運(yùn)行效果:


此時我們的意思是寬作為最大尺寸啦鸣,加之寬高比16:9潮饱,計算出的高效果與不添加一致,若我們改為約束寬:


運(yùn)行效果:


可以看出诫给,當(dāng)我們選擇約束寬時香拉,意思變?yōu)閷捵鳛樽畲蟪叽缋惭铮又?b>高寬比為16:9,計算出的高會比寬要大

既然如此缕溉,那就說明此種情況下寬高的大小是互為影響的考传,我們繼續(xù)修改代碼:


我們將D依賴約束的控件A的寬增加至80dp,觀察效果:


D的寬隨著A的增大而增大证鸥,這同時也會導(dǎo)致D的高隨之增大僚楞,這也是實際應(yīng)用中需要注意的一點

4.鏈(chain)

鏈?zhǔn)且环N特殊的約束布局結(jié)構(gòu),有點像數(shù)據(jù)結(jié)構(gòu)中的雙向鏈表枉层,其定義就是多個控件相互約束而形成的結(jié)構(gòu)泉褐,并擁有頭(head)的概念:


chain

鏈擁有4種風(fēng)格(style):

a.CHAIN_SPREAD:默認(rèn),鏈會正常的分離開(spread out)

b.CHAIN_SPREAD_INSIDE:與默認(rèn)風(fēng)格類似鸟蜡,但此種模式下的鏈頭及鏈尾不會分離開

c.CHAIN_PACKED:此模式下的控件會被打包(packed)在一起膜赃,可以理解為擠在一起而不是分離開,此時指定bias屬性可以改變默認(rèn)的偏移量揉忘,類似我們在居中小節(jié)中介紹的那樣

d.Weighted chain:權(quán)重鏈跳座,在默認(rèn)風(fēng)格的情況下,如果某一個控件使用0dp設(shè)置寬高泣矛,即被設(shè)置為MATCH_CONSTRAINT疲眷,則叫做權(quán)重鏈(*網(wǎng)絡(luò)上有其他教程將其譯作加權(quán)鏈,這是非常明顯的直接套用百度翻譯的結(jié)果您朽,按照官方定義的理解狂丝,此模式更像我們在LinearLayout中使用的權(quán)重(weight)屬性,所以我們依此思路將其叫做權(quán)重鏈更符合原意)哗总。


還記得我們在居中小節(jié)測試代碼現(xiàn)象時几颜,無意中寫出了這種互相約束的鏈結(jié)構(gòu),并在設(shè)置鏈頭的margin時發(fā)現(xiàn)是無效的讯屈,對此官方給出了說明:

在連接處設(shè)定的margin會被計算在內(nèi)蛋哭,而對于spread(默認(rèn))模式下的鏈,設(shè)定的margin會被扣除(If margins are specified on connections, they will be taken in account. In the case of spread chains, margins will be deducted from the allocated space)

按照說明耻煤,CHAIN_SPREAD模式下對鏈頭設(shè)置的margin是無效的具壮,那其他模式應(yīng)該是有效的,我們驗證一下:


上面代碼我們通過指定控件A和C的寬為0dp(MATCH_CONSTRAINT)的形式創(chuàng)建了一組權(quán)重鏈哈蝇,按照官方說明棺妓,非默認(rèn)鏈的情況下鏈頭的margin應(yīng)該是有效的,觀察代碼結(jié)果:


結(jié)果確是如我們所想炮赦,控件A由于只在左右兩邊設(shè)置了約束怜跑,所以設(shè)置的20dp只生效于左右兩邊。

最后,對于其他模式我們沒有太多需要說明性芬,但對于權(quán)重鏈來講峡眶,當(dāng)多個控件被指定為0dp即MATCH_CONSTRAINT后,默認(rèn)它們將用可用空間平分彼此植锉,但你同樣可以使用layout_constraintHorizontal_weight或layout_constraintVertical_weight屬性來指定它們的權(quán)重辫樱,就像我們在LinearLayout中做的那樣,權(quán)重規(guī)則也與LinearLayout中的weight屬性相同俊庇,具體效果我們就不再贅述了狮暑。

5.參照線(Guideline)

Guideline非常像我們PS中經(jīng)常使用的標(biāo)尺,作用也非常相似辉饱,同樣可以用來幫助我們定位控件 但更強(qiáng)大搬男,我們舉個很簡單的例子,如果我現(xiàn)在約束布局中只有一個控件彭沼,那它會因只有父布局可以約束而無法布局在屏幕中的位置缔逛,此時我們便可以設(shè)置Guideline并令控件相對于其做約束來控制控件的位置,Guideline原理上是一個被設(shè)置成View.GONE且寬或高為0的控件姓惑,所以你不會在頁面上真正的看到它褐奴,當(dāng)然Guideline的作用可不僅僅這么簡單,利用Guideline可以讓我們的布局工作變得更加靈活及高效于毙,我們先嘗試一下簡單的例子了解它,另外的章節(jié)我們會結(jié)合實際項目去掌握它望众。

我們可以通過

android:orientation="X"

屬性來在指定方向創(chuàng)建一條Guideline烂翰,X可指定為vertical及horizontal,分別對應(yīng)橫向及豎向的Guideline甘耿,再結(jié)合

app:layout_constraintGuide_X

屬性來指定Guideline來的位置,X可指定為begin佳恬、end及percent,根據(jù)Guideline方向的不同分別代表從上(左)毁葱、下(右)及百分比贰剥,屬性的值代表具體的位置數(shù)值:


我們創(chuàng)建了2條Guideline,一條橫向一條豎向蚌成,并設(shè)置位置為100dp凛捏,然后令控件A約束于它們芹缔,觀察效果:


可以看到坯癣,控件A顯示在了我們期望的位置

結(jié)語:終于,我們深入學(xué)習(xí)完了有關(guān)于ConstraintLayout常用的屬性最欠,也調(diào)試了這些屬性在各種情況下的效果示罗,ConstraintLayout的作用并不僅僅是簡單融合并代替線性布局與相對布局,更是一種全新的布局思想窒所,這種思想甚至將影響我們在頁面動畫動效上的設(shè)計鹉勒,在下一篇文章中,我們將結(jié)合實例去嘗試使用代碼來動態(tài)構(gòu)建ConstraintLayout吵取,并接觸ConstraintLayout真正有用有趣的用法禽额。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市皮官,隨后出現(xiàn)的幾起案子脯倒,更是在濱河造成了極大的恐慌,老刑警劉巖捺氢,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摄乒,居然都是意外死亡悠反,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門馍佑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斋否,“玉大人,你說我怎么就攤上這事拭荤∫鸪簦” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵舅世,是天一觀的道長旦委。 經(jīng)常有香客問我,道長雏亚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任追葡,我火速辦了婚禮,結(jié)果婚禮上匀钧,老公的妹妹穿的比我還像新娘谬返。我一直安慰自己遣铝,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布瘫絮。 她就那樣靜靜地躺著麦萤,像睡著了一般壮莹。 火紅的嫁衣襯著肌膚如雪姻檀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天胶台,我揣著相機(jī)與錄音概作,去河邊找鬼默怨。 笑死匙睹,一個胖子當(dāng)著我的面吹牛济竹,可吹牛的內(nèi)容都是我干的送浊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼闭树,長吁一口氣:“原來是場噩夢啊……” “哼荒澡!你這毒婦竟也來了单山?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤昼接,失蹤者是張志新(化名)和其女友劉穎慢睡,沒想到半個月后膨疏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡者吁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年复凳,在試婚紗的時候發(fā)現(xiàn)自己被綠了育八。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片髓棋。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡按声,死狀恐怖恬吕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渐裂,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布族阅,位于F島的核電站扛拨,受9級特大地震影響绑警,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渴频,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一卜朗、第九天 我趴在偏房一處隱蔽的房頂上張望场钉。 院中可真熱鬧,春花似錦逛万、人聲如沸宇植。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茬斧。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間库糠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工罢防, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留唉侄,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓恬叹,卻偏偏與公主長得像绽昼,于是被迫代替她去往敵國和親硅确。 傳聞我的和親對象是個殘疾皇子明肮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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