1、概述
ConstraintLayout 佈局已經出來有一兩年了,最早開始由於視圖化的佈局,因此一直沒有使用過,最近瀏覽其餘博客的時候,屢次看到ConstraintLayout 是官方推薦使用的佈局,並且相對於其餘的四大布局,有不少性能方面的優點。因此有必要學習和使用一下這個佈局。下面開始吧!
引入依賴(已經到1.1版本了,是應該多嘗試使用這個佈局了)android
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
2、效果展現
不喜歡視圖化佈局,其實也能夠手寫屬性來佈局。下面展現下我看hongyang大神博客時手寫佈局的效果。
下面是佈局xml代碼:markdown
<?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"> <ImageView android:id="@+id/img_banner" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="15dp" android:background="@color/colorPrimaryDark" app:layout_constraintDimensionRatio="H,16:9" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <ImageView android:id="@+id/img_left" android:layout_width="146dp" android:layout_height="86dp" android:layout_marginBottom="10dp" android:layout_marginLeft="12dp" android:layout_marginTop="10dp" android:background="@color/colorPrimary" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/img_banner" /> <TextView android:id="@+id/txt_content" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:text="馬雲:一年交稅170多億馬雲:一年交稅170多億馬雲:一年交稅170多億" app:layout_constraintLeft_toRightOf="@+id/img_left" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@+id/img_left" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:text="8分鐘前" app:layout_constraintBottom_toBottomOf="@+id/img_left" app:layout_constraintLeft_toLeftOf="@+id/txt_content" /> <TextView android:layout_width="60dp" android:layout_height="60dp" android:background="@color/colorPrimary" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintHorizontal_bias="0.9" app:layout_constraintVertical_bias="0.9"/> <TextView android:id="@+id/tab1" android:layout_width="0dp" android:layout_height="40dp" android:background="@android:color/darker_gray" android:gravity="center" android:text="tab1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/tab2" /> <TextView android:id="@+id/tab2" android:layout_width="0dp" android:layout_height="40dp" android:background="@android:color/holo_green_light" android:gravity="center" android:text="tab1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintLeft_toRightOf="@+id/tab1" app:layout_constraintRight_toLeftOf="@+id/tab3" /> <TextView android:id="@+id/tab3" android:layout_width="0dp" android:layout_height="40dp" android:background="@android:color/holo_red_light" android:gravity="center" android:text="tab1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintLeft_toRightOf="@+id/tab2" app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>
3、屬性介紹
結合這個上面這個佈局介紹下ConstraintLayout的屬性吧app
一、相對位置(Relative positioning)
在橫向和縱向上添加約束關係來固定控件位置,官方一共提供給咱們這些相對約束屬性:
下面咱們對比下效果
沒有添加約束佈局
<?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/btn_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按鈕01"/> <Button android:id="@+id/btn_02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按鈕2"/> </android.support.constraint.ConstraintLayout>
沒有添加按鈕2在按鈕1的右邊的約束性能
<?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/btn_01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按鈕01"/> <Button android:id="@+id/btn_02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按鈕2" app:layout_constraintLeft_toRightOf="@+id/btn_01"/> </android.support.constraint.ConstraintLayout>
僅僅添加了一個app:layout_constraintLeft_toRightOf="@+id/btn_01"
屬性就能夠達到了RelativeLayout佈局的android:layout_toLeftOf="@id/btn_1"
所要的效果。
相對位置的約束屬性的格式基本是layout_constraintxxx_toxxxOf=id這種格式,理解起來其實並不難,constraintxxx
表明當前控件的約束方向,如上圖的效果constraintLeft就是就是btn_02按鈕的左邊約束。toxxxOf
被約束的控件的方向,如上圖id是btn_01 就表明與id爲btn_01控件的右邊方向約束在一塊兒。app:layout_constraintLeft_toRightOf="@+id/btn_01"
結合起來就是當前控件btn_01按鈕的左邊與id爲btn_01的控件的右邊相約束。 關於約束這個詞的理解,你能夠理解成用帶彈性的繩子相鏈接起來。
下面在展現幾個例子:
學習
<?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/btn_01" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:text="按鈕01"/> <Button android:id="@+id/btn_02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按鈕2" app:layout_constraintLeft_toLeftOf="@+id/btn_01" app:layout_constraintTop_toBottomOf="@+id/btn_01" app:layout_constraintRight_toRightOf="@+id/btn_01"/> </android.support.constraint.ConstraintLayout>
首先對按鈕01 使用app:layout_constraintLeft_toLeftOf="parent"
和app:layout_constraintTop_toTopOf="parent"
使得按鈕01的左邊和頂部與父佈局的左邊和頂部約束,這樣按鈕就被固定在左上角。 而後對按鈕02 使用app:layout_constraintLeft_toLeftOf="@+id/btn_01"
將按鈕02的左邊與按鈕01的左邊相約束,而後使用app:layout_constraintTop_toBottomOf="@+id/btn_01"
讓按鈕02的頂部與按鈕01的底部相約束,這樣按鈕02就在按鈕01的正下方。最後使用 app:layout_constraintRight_toRightOf="@+id/btn_01"
讓按鈕02的右邊與按鈕01的右邊相約束,保持永遠對齊。google
二、傾向(bias)
傾向分爲兩個方向 橫向和縱向, 也就是說左右和上下兩邊出現受力不均,形成傾向,好比左邊約束的力是右邊約束的力之比是9:1atom
<?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/btn_01" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_marginLeft="80dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:text="按鈕01"/> <Button android:id="@+id/btn_02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按鈕2" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintVertical_bias="0.3" app:layout_constraintHorizontal_bias="0.9"/> </android.support.constraint.ConstraintLayout>
理解:左邊的間距佔左右邊間距之和的90%,上間距占上下間距之和的30%spa
三、圓心定位
這是在1.1版本添加的新屬性,貌似沒有自動提示
.net
<?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/btn_01" android:layout_width="80dp" android:layout_height="wrap_content" android:layout_marginLeft="80dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:text="按鈕01"/> <Button android:id="@+id/btn_02" android:layout_width="80dp" android:layout_height="wrap_content" android:text="按鈕2" app:layout_constraintCircle="@+id/btn_01" app:layout_constraintCircleRadius="90dp" app:layout_constraintCircleAngle="20"/> </android.support.constraint.ConstraintLayout>
圓心定位意思就是基於兩個控件的中心,經過radius和angle來控制控件的位置。angle角度不支持負值。默認以被定位控件(btn_01)的Y軸正方向爲零度。
四、可見性約束
能夠看到區別開始是按鈕01左邊約束父佈局的左邊,而後按鈕02約束按鈕01的右邊。 可是當按鈕01隱藏之後,按鈕02直接約束到父佈局的左邊,事實上按鈕根本沒有約束父佈局的左邊。 這裏小編的理解,就是以前的隱藏的控件的佈局約束依然有效,只不過按鈕01的全部邊距變成了0.若是你有更好的理解請告訴我,謝謝。
五、控件尺寸約束
一般咱們定義控件的長和寬,android:layout_width=""
和android:layout_height=""
來設置控件的大小。
ConstraintLayout佈局設置方式:
- 固定值
- wrap_content
- 0dp(至關於MATCH_CONSTRAINT)
那match_parent呢?看下面這段話
Important: MATCH_PARENT is not recommended for widgets contained in a ConstraintLayout. Similar behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom constraints being set to 「parent」.
大概意思是不推薦使用match_parent在ConstraintLayout佈局中設置大小,相似的功能可使用約束設置左右或者上下指定約束到父佈局上。
那怎樣實現其餘四大布局match_parent沾滿父窗體剩下控件的效果呢? 可使用0dp來代替
match_parent的效果
<?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/btn_01" android:layout_width="80dp" android:layout_height="wrap_content" android:layout_marginLeft="48dp" android:layout_marginTop="112dp" android:text="按鈕01" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"/> <Button android:id="@+id/btn_02" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="按鈕2" app:layout_constraintLeft_toRightOf="@+id/btn_01" app:layout_constraintRight_toRightOf="parent"/> </android.support.constraint.ConstraintLayout>
0dp實現的效果
<?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/btn_01" android:layout_width="80dp" android:layout_height="wrap_content" android:layout_marginLeft="48dp" android:layout_marginTop="112dp" android:text="按鈕01" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent"/> <Button android:id="@+id/btn_02" android:layout_width="0dp" android:layout_height="wrap_content" android:text="按鈕2" app:layout_constraintLeft_toRightOf="@+id/btn_01" app:layout_constraintRight_toRightOf="parent"/> </android.support.constraint.ConstraintLayout>
六、比例(Ratio)
app:layout_constraintDimensionRatio="H,16:9" app:layout_constraintDimensionRatio="W,16:9"
這裏的比例指的是佔父佈局的高度和寬度的比例
七、鏈條(Chains)
鏈條適合於橫向或者縱向一排的控件的佈局方式。
首先要建立一個鏈條,就是一排控件首位相互約束,以下圖
相似的效果的代碼像這樣,建立了一個鏈條
<?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"> <TextView android:id="@+id/tab1" android:layout_width="0dp" android:layout_height="40dp" android:background="@android:color/darker_gray" android:gravity="center" android:text="tab1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/tab2" /> <TextView android:id="@+id/tab2" android:layout_width="0dp" android:layout_height="40dp" android:background="@android:color/holo_green_light" android:gravity="center" android:text="tab1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/tab1" app:layout_constraintRight_toLeftOf="@+id/tab3" /> <TextView android:id="@+id/tab3" android:layout_width="0dp" android:layout_height="40dp" android:background="@android:color/holo_red_light" android:gravity="center" android:text="tab1" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/tab2" app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>
效果就像這樣
看似效果跟LinearLayout的比重佈局很類似,可是它有和LinearLayout不同的效果,就是給鏈條添加樣式。
- CHAIN_SPREAD 元素被分散開(默認樣式)
- 在CHAIN_SPREAD模式下,若是一些控件被設置爲MATCH_CONSTRAINT,那麼控件將會把全部剩餘的空間均分後「吃掉」
- CHAIN_SPREAD_INSIDE Chain兩邊的元素貼着父容器,其餘元素在剩餘的空間中採用CHAIN_SPREAD模式
- CHAIN_PACKED Chain中的全部控件合併在一塊兒後在剩餘的空間中居中
4、總結
看完了關於ConstraintLayout佈局屬性的介紹,是否是感受很是強大,不只有豐富的相對位置約束,還有比例、傾向的設置,具有RelativeLayout
和LinearLayout
兩個最經常使用佈局的各類優勢。關鍵在性能上也有優點,咱們還有什麼理由不嘗試呢?
參考連接:
https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout
http://www.javashuo.com/article/p-vvqpebme-bt.html