一、概述
ConstraintLayout(約束布局),是Google在2016年推出的一種布局,其簡單、扁平化的使用方式,深得廣大開發(fā)者的喜愛。這篇文章我們不探討其性能方面的優(yōu)勢。意在于和大家一起學(xué)習(xí)ConstraintLayout的相關(guān)使用。
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
二、可視化界面的使用
Android Studio 2.2開始提供了對ConstraintLayout可視化的操作。對于可視化操作方面內(nèi)容。這里大家可以通過郭霖大神的博客進(jìn)行學(xué)習(xí)。
三、屬性介紹
屬性介紹是我們ConstraintLayout重點(diǎn)要學(xué)習(xí)的部分??梢暬缑嬷皇呛喕宋覀兪褂?,對它所使用的屬性,我們要至少知道其意,并可以進(jìn)行簡單的修改和手寫布局。
1、相對位置屬性
- layout_constraintLeft_toLeftOf :當(dāng)前View的左側(cè)和另一個(gè)View的左側(cè)位置對齊
- layout_constraintLeft_toRightOf :當(dāng)前view的左側(cè)會(huì)在另一個(gè)View的右側(cè)位置
- layout_constraintRight_toLeftOf :當(dāng)前view的右側(cè)會(huì)在另一個(gè)View的左側(cè)位置
- layout_constraintRight_toRightOf :當(dāng)前View的右側(cè)和另一個(gè)View的右側(cè)位置對齊
- layout_constraintTop_toTopOf :頭部對齊
- layout_constraintTop_toBottomOf :當(dāng)前View在另一個(gè)View的下側(cè)
- layout_constraintBottom_toTopOf :當(dāng)前View在另一個(gè)View的上方
- layout_constraintBottom_toBottomOf :底部對齊
- layout_constraintBaseline_toBaselineOf :文字底部對齊
- layout_constraintStart_toEndOf :同left_toRightOf
- layout_constraintStart_toStartOf :同left_toLeftOf
- layout_constraintEnd_toStartOf :同right_toLeftOf
- layout_constraintEnd_toEndOf :同right_toRightOf
從ConstraintLayout的相對位置屬性可以看出和我們的RelativeLayout很相似,這也是有人將ConstraintLayout成為增強(qiáng)型的相對布局的原因,不過,其實(shí)現(xiàn)思想是完全不同的。從下面的例子我們可以看出來。
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btA"
android:layout_width="148dp"
android:layout_height="wrap_content"
android:text="ButtonA"
/>
<Button
android:id="@+id/btB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ButtonB"
android:layout_toRightOf="@id/btA"
android:layout_alignParentRight="true"
/>
</RelativeLayout>
在圖片1-1中,我們使用RelativeLayout布局實(shí)現(xiàn)ButtonB在ButtonA的右側(cè)并填滿右側(cè)空間,我們將ButtonB的width設(shè)置為wrap_content,并且使用 android:layout_toRightOf="@id/btA"和android:layout_alignParentRight="true"兩個(gè)相對屬性。現(xiàn)在我們將布局改為ConstraintLayout并將相對屬性改為app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_to
EndOf="@+id/buttonB"
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="buttonB"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/buttonA" />
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="buttonA"
/>
</android.support.constraint.ConstraintLayout>
我們通過對比可以發(fā)現(xiàn)ButtonB同樣是wrap_content,但是我們的RelativeLayout會(huì)改變我們的View大小。而ConstraintLayout并不會(huì),他會(huì)像橡皮筋一樣拉著我們的View使他在我們的右側(cè)居中。并不會(huì)改變view的大小。當(dāng)我們的View寬度足夠大的時(shí)候超過了我們又側(cè)剩余寬度。也只是如1-3一樣,左右兩側(cè)的約束一樣大,使之感覺還是居中的。寬度還是我們設(shè)置的寬度并未被改變
接下來,如果我們想要讓我們的ConstraintLayout實(shí)現(xiàn)的效果和RelativeLayout一樣。官方給我們提供了一個(gè)match_constrain也就是0dp,我們?yōu)锽uttonB的寬度設(shè)置為match_constrain(0dp)就可以將我們的ButtonB填滿我們右側(cè)的布局了。而官方對match_constrain的解釋為
- Important: MATCH PARENT is not supported for widgets contained in a ConstraintLayout, though similar behavior can be defined by using MATCH CONSTRAINT with the corresponding left/right or top/bottom constraints being set to “parent”.
可以理解為在ConstraintLayout中已經(jīng)不支持MATCH_PARENT,你可以通過MATCH_CONSTRAINT配合約束實(shí)現(xiàn)類似的效果。
理解了上面的內(nèi)容我們來看一下類似的內(nèi)容:強(qiáng)制約束。當(dāng)我們的ButtonB的width設(shè)置為wrap_content的時(shí)候,而我們的ButtonB的內(nèi)容過長就會(huì)像下圖一樣。導(dǎo)致約束失效。
而為了防止約束失效,在1.1.0版本中新增了一下屬性。
- app:layout_constrainedWidth=”true|false” //默認(rèn)false
- app:layout_constrainedHeight=”true|false” //默認(rèn)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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="buttonA"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="buttonbuttonbuttonbuttonbuttonbuttonbutton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/buttonA"
app:layout_constrainedWidth="true"
/>
</android.support.constraint.ConstraintLayout>
2、GoneMargin
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
我們對Margin這個(gè)屬性應(yīng)該很熟悉,GoneMargin也很簡單,他的含義就是當(dāng)一個(gè)控件和另一個(gè)控件綁定后,如果另一個(gè)控件設(shè)置為Gone則,GoneMargin這組屬性會(huì)生效。
<?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">
<Button
android:id="@+id/buttonA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="buttonA"
android:visibility="gone"
/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="buttonB"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/buttonA"
app:layout_goneMarginLeft="40dp"
/>
</android.support.constraint.ConstraintLayout>
3、Chains(鏈)
鏈?zhǔn)刮覀兡軌驅(qū)σ唤M在水平或豎直方向互相關(guān)聯(lián)的控件的屬性進(jìn)行統(tǒng)一管理。成為鏈的條件:一組控件它們通過一個(gè)雙向的約束關(guān)系鏈接起來,首尾對parent約束。 并且鏈的屬性是由一條鏈的頭結(jié)點(diǎn)控制的,如下:
Chains Style:鏈的樣式有三種packed,spread_inside,spread
app:layout_constraintHorizontal_chainStyle="packed | spread_inside | spread"
- Spread Chain:Style為spread的時(shí)候。
- Spread Chain:Style為spread_inside的時(shí)候。
- Weighted Chain:當(dāng)Style為spread,width為0dp,可以使用Weighted屬性等分(Weighted屬性和線性布局的weighted用法相同)
- Packed Chain 當(dāng)Style為packed的時(shí)候。
- Packed Chain with Bias,當(dāng)Style為packed,并且設(shè)置了Bias屬性。Bias屬性下部分會(huì)講解
<?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/bt_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="A"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toStartOf="@+id/bt_2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/bt_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"
app:layout_constraintEnd_toStartOf="@+id/bt_3"
app:layout_constraintStart_toEndOf="@+id/bt_1"
app:layout_constraintTop_toTopOf="@+id/bt_1" />
<Button
android:id="@+id/bt_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="c"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bt_2"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
4、MATCH_CONSTRAINT
上邊我們說過ConstraintLayout取消了MATCH_PARENT由MATCH_CONSTRAINT來代替,默認(rèn)大小占用所有約束可用空間,并提供了以下屬性輔助我們使用。
- layout_constraintWidth_min 設(shè)置最小寬度
- layout_constraintHeight_min 設(shè)置最小高度
- layout_constraintWidth_max 設(shè)置最大寬度
- layout_constraintHeight_max 設(shè)置最大高度
- layout_constraintWidth_percent 設(shè)置寬度相對父類寬度百富比
- layout_constraintHeight_percent 設(shè)置高度相對父類高度的百分比
5、百分比布局
約束布局支持子控件設(shè)置寬高比,前提條件是至少需要將寬高中的一個(gè)設(shè)置為0dp。為了約束一個(gè)特定的邊,基于另一個(gè)邊的尺寸,可以預(yù)先附加W,或H以逗號隔開。
<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">
<Button
android:layout_width="0dp"
android:layout_height="0dp"http://高度基于寬度的尺寸所以高度為0dp,否則百分比屬性無效
android:text="A"
app:layout_constraintDimensionRatio="H,16:9"http://約束高度基于寬度的尺寸。
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
6、Guideline 輔助線
Guideline輔助線是一條寬或高為0dp的一個(gè)看不見的線,和LinearLayout一樣都有orientation屬性設(shè)置橫向或垂直。有三種定位方式
- layout_constraintGuide_begin 距離父容器起始位置的距離(左側(cè)或頂部)垂直的輔助線使用
- layout_constraintGuide_end 距離父容器結(jié)束位置的距離(右側(cè)或底部)水平的輔助線使用
- layout_constraintGuide_percent 距離父容器寬度或高度的百分比(垂直或水平的輔助線都可以使用)
例:設(shè)置一條垂直方向距離父控件左側(cè)為100dp的Guideline:
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="100dp"
android:layout_height="wrap_content"/>
7、Group為ConstraintLayout布局中的子控件進(jìn)行分組,可控制多個(gè)布局控件統(tǒng)一的可見性
<android.support.constraint.Group
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"http://設(shè)置可見性
app:constraint_referenced_ids="bt1,bt2"http://要管理的控件id
/>
<Button
android:id="@+id/bt1"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="A"
/>
<Button
android:id="@+id/bt2"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="A"
/>
8、Barrier,屏障,在約束布局中,可以將幾個(gè)View作為一個(gè)整體來使用,讓其他布局關(guān)聯(lián)約束這個(gè)整體。注意設(shè)置他的visibility不能控制這個(gè)整體的可見性。我們看一個(gè)例子。
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名:"
app:layout_constraintBottom_toBottomOf="@+id/et_name"
app:layout_constraintTop_toTopOf="@+id/et_name"/>
<TextView
android:id="@+id/tv_contract"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="聯(lián)系方式:"
app:layout_constraintBottom_toBottomOf="@+id/et_contract"
app:layout_constraintTop_toTopOf="@+id/et_contract"/>
<EditText
android:id="@+id/et_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="請輸入姓名"
app:layout_constraintLeft_toLeftOf="@+id/barrier"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<EditText
android:id="@+id/et_contract"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="請輸入聯(lián)系方式"
app:layout_constraintLeft_toLeftOf="@+id/barrier"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_name"/>
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="right"
app:constraint_referenced_ids="tv_name,tv_contract"/>
這里我們把A區(qū)域中的姓名和聯(lián)系方式用Barrier關(guān)聯(lián)成一個(gè)整體。而右側(cè)的B區(qū)域中的EditText分別關(guān)聯(lián)約束這個(gè)Barrier整體。當(dāng)Barrier整體中的TextView的寬度發(fā)生改變時(shí),Barrier整體也是變化的,右側(cè)的B區(qū)域的寬度也會(huì)隨之改變。
9、Circular positioning (圓形定位)
- 您可以將一個(gè)控件的中心以一定的角度和距離約束到另一個(gè)控件的中心,相當(dāng)于在一個(gè)圓上放置一個(gè)控件。
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
//引用的控件ID
app:layout_constraintCircle="@+id/buttonA"
//圓半徑
app:layout_constraintCircleRadius="100dp"
//偏移圓角度 水平右方向?yàn)?逆時(shí)針方向旋轉(zhuǎn)
app:layout_constraintCircleAngle="45" />
10、bias 權(quán)重
- 當(dāng)一個(gè)控件擁有水平方向(左右兩個(gè)約束)或者垂直方向(上下兩個(gè)約束)的時(shí)候,我們可以通過app:layout_constraintHorizontal_bias
="0.16"或 app:layout_constraintVertical_bias="0.303"兩個(gè)屬性來對兩個(gè)方向的約束進(jìn)行百分比的調(diào)整。讓控件按百分比偏向一方。當(dāng)不設(shè)置是默認(rèn)是0.5居中的效果。
<Button
android:id="@+id/bt1"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="A"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
參考文章: