地址:http://www.jianshu.com/p/38ee0aa654a8
1寫在前面
之前品讀了郭霖大神寫的《Android新特性介紹,ConstraintLayout完全解析》(http://blog.csdn.net/guolin_blog/article/details/53122387),受其感染,寫了一篇《未來布局之星——ConstraintLayout》(http://www.jianshu.com/p/c34ce21f77b3),回過頭來看,感覺這一篇文章太注重可視化操作,于是去翻閱了一下ConstraintLayout的官方文檔,決定從官方文檔的角度在代碼層面來了解一下ConstraintLayout。
2
繼承關(guān)系
ConstraintLayout和其他布局一樣,繼承自ViewGroup,但是不同點在于它調(diào)整控件的位置和大小時更加得靈活,功能更加強大。
3
版本支持
ConstraintLayout是一個Support庫,意味著向前兼容,它可以兼容至API 9,也就是Android 2.3,鑒于現(xiàn)在市場上手機基本都是2.3及以上的,所以如果不是特殊情況,開發(fā)者可以不用考慮版本問題。下面是官網(wǎng)文檔引文:
Note: ConstraintLayout is available as a support library that you can use on Android systems starting with API level 9 (Gingerbread).
4
新特性
相對于傳統(tǒng)布局,ConstraintLayout在以下方面提供了一些新的特性:
相對定位
外邊距
居中和傾向
可見性的表現(xiàn)
尺寸約束
Chain
輔助工具
接下來就這些新特性進行詳細(xì)了解。
5
相對定位
相對定位是在ConstraintLayout中創(chuàng)建布局的最基本構(gòu)建塊,也就是一個控件相對于另一個控件進行定位,可以從橫向、縱向添加約束關(guān)系,用到的邊分別有:
橫向:Left、Right、Start、End
縱向:Top、Bottom、Baseline(文本底部的基準(zhǔn)線)
通常是一條邊向另一條邊添加約束,就像下面按鈕B要定位在按鈕A的右邊一樣:
這種情況代碼實現(xiàn)是這樣的:
這樣系統(tǒng)就會知道按鈕B的左側(cè)被約束在按鈕A的右側(cè),這里的約束可以理解為邊的對齊。
上圖是相對定位的約束,圖中每一條邊(top、bottom、baseline、left、start、right、end)都可以與其他控件形成約束,羅列這些邊形成的相對定位關(guān)系如下:
上面的這些屬性需要結(jié)合id才能進行約束,這些id可以指向控件也可以指向父容器(也就是ConstraintLayout),比如:
6
外邊距
這里的外邊距相信大家都理解,這里就不贅述了,羅列外邊距的屬性如下:
來主要看一下外邊距的新屬性:GONE MARGIN
以圖 3為例,這里的gone margin指的是B向A添加約束后,如果A的可見性變?yōu)镚ONE,這時候B的外邊距可以改變,也就是B的外邊距根據(jù)A的可見性分為兩種狀態(tài)。
7
居中和傾向
居中
在相對定位一小節(jié),我們了解了兩個控件之間添加約束,現(xiàn)在來看看一個控件和父布局(ConstraintLayout)建立約束。當(dāng)相同方向上(橫向或縱向),控件兩邊同時向ConstraintLayout添加約束,情況就會像圖 4所示的這樣。
而代碼的書寫是這樣的:
這種情況就感覺像是控件兩邊有兩個反向相等大小的力在拉動它一樣,所以才會產(chǎn)生控件居中的效果。
這里說明一下:如果在居中方向上(橫向或縱向)控件的尺寸和ConstraintLayout的尺寸一樣,那么就無所謂居中了,此時約束的存在是沒有意義的。
傾向
在這種約束是同向相反的情況下,默認(rèn)控件是居中的,但是也可以像拔河一樣,讓兩個約束的力大小不等,這樣就產(chǎn)生了傾向,其屬性是:
下面這段代碼就是讓左邊占30%,右邊占70%(默認(rèn)兩邊各占50%),這樣左邊就會短一些,如圖5所示,此時代碼是這樣的:
通過設(shè)置傾向,可以非常便捷地實現(xiàn)屏幕適配。
8
可見性的表現(xiàn)
ConstraintLayout對可見性被標(biāo)記View.GONE的控件(后稱“GONE控件”)有特殊的處理。一般情況下,GONG控件是不可見的,且不再是布局的一部分,但是在布局計算上,ConstraintLayout與傳統(tǒng)布局有一個很重要的區(qū)別:
傳統(tǒng)布局下,GONE控件的尺寸會被認(rèn)為是0(當(dāng)做點來處理)
在ConstraintLayout中,GONE控件尺寸仍然按其可見時的大小計算,但是其外邊距大小按0計算
這種特殊的行為讓我們在無需打亂布局情況下,在標(biāo)記GONE控件的地方構(gòu)建布局,這樣的做法對于做簡單的布局動畫很有用。
說明一下:筆者在理解原文這句話的時候不是很理解,希望有經(jīng)驗的讀者可以指點迷津,原文如下:
This specific behavior allows to build layouts where you can temporarily mark widgets as being GONE, without breaking the layout (Fig. 6), which can be particularly useful when doing simple layout animations.
關(guān)于目標(biāo)控件(如圖 6中的A)設(shè)置為GONE時,受約束的控件(如圖 6中的B)的外邊距的變化設(shè)置請查看上面的外邊距小節(jié)的GONE MARGIN屬性。
Note:The margin used will be the margin that B had defined when connecting to A (see Fig. 6 for an example). In some cases, this might not be the margin you want (e.g. A had a 100dp margin to the side of its container, B only a 16dp to A, marking A as gone, B will have a margin of 16dp to the container). For this reason, you can specify an alternate margin value to be used when the connection is to a widget being marked as gone (see the section above about the gone margin attributes).
9
尺寸約束
ConstraintLayout中的最小尺寸
ConstraintLayout本身可以定義自己的最小尺寸:
android:minWidth 設(shè)置布局的最小寬度
android:minHeight 設(shè)置布局的最小高度
這些最小尺寸當(dāng)ConstraintLayout被設(shè)置為WRAP_CONTENT時有效。
控件尺寸約束
控件的尺寸可以通過android:layout_width和android:layout_height來設(shè)置,有三種方式:
使用固定值
使用WRAP_CONTENT
使用0dp(相當(dāng)于MATCH_CONSTRAINT)
前兩種方式和其他布局的用法相同,最后一種是通過填充約束來重新設(shè)置控件的尺寸(如圖 7,(a)是wrap_content,(b)是0dp)。代碼案例如下:
如果控件設(shè)置了外邊距,那么外邊距就會在尺寸計算中被考慮進去,效果如圖圖 7 (c)所示。
敲黑板,劃重點:一般MATCH_PARENT在ConstraintLayout布局下是不支持的,但是在簡單的布局結(jié)構(gòu)(如控件的約束只與ConstraintLayout關(guān)聯(lián))下,MATCH_PARENT是被支持的,其作用與MATCH_CONSTRAINT相同。
比例
這里的比例指的是寬高比,通過設(shè)置比例,讓寬高的其中一個隨另一個變化。為了實現(xiàn)比例,需要讓控件寬或高受約束,且尺寸設(shè)置為0dp(也可以是MATCH_CONSTRAINT),實現(xiàn)代碼如下:
上述代碼中,按鈕的高度滿足受約束且設(shè)置為0dp的條件,所以其尺寸會按照比例隨寬度調(diào)整。
比例的設(shè)置有兩種格式:
寬度與高度的比,可理解為受約束的一方尺寸:另一方尺寸
受約束的一方尺寸/另一方尺寸得到的浮點數(shù)值
如果寬高都設(shè)置了MATCH_CONSTRAINT(0dp)和約束,那么需要在比例前添加W,或H,以確定受約束的是高還是寬,然后受約束的一方根據(jù)不受約束的一方,按照比例計算自己的尺寸。
關(guān)于上面這段話,原文是:
You can also use ratio if both dimensions are set to MATCH_CONSTRAINT (0dp). In this case the system sets the largest dimensions the satisfies all constraints and maintains the aspect ratio specified. To constrain one specific side based on the dimensions of another. You can pre append W," or H, to constrain the width or height respectively.
筆者個人感覺官方文檔對于這一塊表述較模糊,可能跟自己的英語閱讀能力有關(guān),望有經(jīng)驗的過來人答疑解惑。
關(guān)于上述的案例,代碼如下:
上述代碼對寬度和高度都進行了約束,通過H,指定高度受約束,所以高度的尺寸會根據(jù)寬度大小按照比例得到,其效果如圖所示:
至于為何高度填充屏幕而寬度不填充,其玄機在于下面這句話,能理解它,就理解了比例使用的精髓:
In this case the system sets the largest dimensions the satisfies all constraints and maintains the aspect ratio specified.
10
Chain
Chain是一系列雙向連接的控件連接在一起的形態(tài)(如圖 8所示,是最小單位的Chain,只有兩個組件)。
Chain頭部
橫向上,Chain頭部是Chain最左邊的控件;縱向上,Chain頭部是Chain最頂部的控件。
Chain外邊距
如果連接時定義了外邊距,Chain就會發(fā)生變化。在SPREAD CHAIN中,外邊距會從已經(jīng)分配好的空間中去掉。原文如下:
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樣式
當(dāng)對Chain的第一個元素設(shè)置layout_constraintHorizontal_chainStyle或layout_constraintVertical_chainStyle屬性,Chain就會根據(jù)特定的樣式(默認(rèn)樣式為CHAIN_SPREAD)進行相應(yīng)變化,樣式類型如下:
CHAIN_SPREAD 元素被分散開(默認(rèn)樣式)
在CHAIN_SPREAD模式下,如果一些控件被設(shè)置為MATCH_CONSTRAINT,那么控件將會把所有剩余的空間均分后“吃掉”
CHAIN_SPREAD_INSIDE Chain兩邊的元素貼著父容器,其他元素在剩余的空間中采用CHAIN_SPREAD模式
CHAIN_PACKED Chain中的所有控件合并在一起后在剩余的空間中居中
帶權(quán)重的Chain
默認(rèn)的Chain會在空間里平均散開。如果其中有一個或多個元素使用了MATCH_CONSTRAINT屬性,那么他們會將剩余的空間平均填滿。屬性layout_constraintHorizontal_height和layout_constraintVertical_weight控制使用MATCH_CONSTRAINT的元素如何均分空間。
例如,一個Chain中包含兩個使用MATCH_CONSTRAINT的元素,第一個元素使用的權(quán)重為2,第二個元素使用的權(quán)重為1,那么被第一個元素占用的空間是第二個元素的2倍。
輔助工具
這里“輔助工具”的原文是Virtual Helper objects,對于ConstraintLayout,其輔助工具目前是Guidline。關(guān)于Guideline的了解,讀者們可先嘗試《未來布局之星——ConstraintLayout》一文中的Guideline操作。在此基礎(chǔ)上,訪問Guideline(https://developer.android.google.cn/reference/android/support/constraint/Guideline.html)類了解詳情,附上Guideline類的代碼案例供讀者們了解:
11
相關(guān)方法
Public構(gòu)造方法
ConstraintLayout(Contextcontext)
ConstraintLayout(Contextcontext,AttributeSetattrs)
ConstraintLayout(Contextcontext,AttributeSetattrs, int defStyleAttr)
Public方法
voidaddView(Viewchild, int index,ViewGroup.LayoutParamsparams)
ConstraintLayout.LayoutParamsgenerateLayoutParams(AttributeSetattrs)
intgetMaxHeight()
intgetMaxWidth()
intgetMinHeight()
intgetMinWidth()
voidonViewAdded(Viewview)
voidonViewRemoved(Viewview)
voidremoveView(Viewview)
voidrequestLayout()
voidsetConstraintSet(ConstraintSetset)
voidsetMaxHeight(int value)
voidsetMaxWidth(int value)
voidsetMinHeight(int value)
voidsetMinWidth(int value)
Protected方法
booleancheckLayoutParams(ViewGroup.LayoutParamsp)
ConstraintLayout.LayoutParamsgenerateDefaultLayoutParams()
ViewGroup.LayoutParamsgenerateLayoutParams(ViewGroup.LayoutParamsp)
voidonLayout(boolean changed, int left, int top, int right, int bottom)
voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)
12
寫在最后 第一次用所剩無幾的英語能力蹩腳地翻譯官方文檔,看著密密麻麻的英文寫到這里,如今已經(jīng)頭昏眼花、不知所云,若讀者們有發(fā)現(xiàn)文章錯誤的地方,歡迎在文章下方評論留言。個人感覺,想要深入理解ConstraintLayout,還是需要多使用、多實踐,并且要結(jié)合源碼分析,但愿通過這篇文章的學(xué)習(xí),讀者們可以達(dá)到入門ConstraintLayout的目的。翻譯不易,轉(zhuǎn)載請注明鏈接,最后附上官方文檔的地址,供讀者們比對學(xué)習(xí),感謝閱讀!
https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout.html
code小生欄目
CSDN:
http://blog.csdn.net/wufeng55
簡書:
http://www.jianshu.com/u/645342ca3cad
End
長
按
關(guān)
注