ConstraintLayout_2:手寫代碼佈局 前言 編寫一個列表item 和RelativeLayout的差異 增加一個banner 增加幾個Tab 增加浮動按鈕 嘗試使用Guideline

轉自博客:http://blog.csdn.net/lmj623565791/article/details/78011599

前言

承接上篇文章,ConstraintLayout用可視化拖拽的方式佈局雖然方便,但是知其然而不知其所以然。最好的方法還是自己手寫屬性,雖然一開始麻煩一點,但是最爲穩妥,佈局出了問題也最好定位。這篇文章就記錄各種屬性的使用方法。

編寫一個列表item

<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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#11ff0000"
    tools:context="com.zhy.constrantlayout_learn.MainActivity">


    <TextView
        android:id="@+id/tv1"
        android:layout_width="140dp"
        android:layout_height="86dp"
        android:layout_marginLeft="12dp"
        android:layout_marginTop="12dp"
        android:background="#fd3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <TextView
        android:id="@+id/tv2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="12dp"
        android:text="馬雲:一年交稅170多億馬雲:一年交稅170多億馬雲:一年交稅170多億"
        android:textColor="#000000"
        android:textSize="16dp"
        app:layout_constraintLeft_toRightOf="@id/tv1"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@id/tv1" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="12dp"
        android:text="8分鐘前"
        android:textColor="#333"
        android:textSize="12dp"
        app:layout_constraintLeft_toRightOf="@id/tv1"
        app:layout_constraintBottom_toBottomOf="@id/tv1" />

</android.support.constraint.ConstraintLayout>

看上面的佈局,我們好像看到了幾個模式的屬性:

首先是tv1,有兩個沒見過的屬性:

  • app:layout_constraintLeft_toLeftOf="parent"
    從字面上看,指的是讓該控件的左側與父佈局對齊,當我們希望控件A與控件B左側對齊時,就可以使用該屬性。
app:layout_constraintLeft_toLeftOf="@id/viewB"

類似的還有個相似的屬性爲:

  • app:layout_constraintLeft_toRightOf
    很好理解,即當前屬性的左側在誰的右側,當我們希望控件A在控件B的右側時,可以設置:
app:layout_constraintLeft_toRightOf="@id/viewB"

與之類似的還有幾個屬性:

  • layout_constraintRight_toLeftOf
  • layout_constraintRight_toRightOf
  • layout_constraintTop_toTopOf
  • layout_constraintTop_toBottomOf
  • layout_constraintBottom_toTopOf
  • layout_constraintBottom_toBottomOf
  • layout_constraintBaseline_toBaselineOf

類推就可以了。

現在再看剛纔的佈局:

tv1設置了:

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"

tv2設置了:

app:layout_constraintLeft_toRightOf="@id/tv1"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/tv1"

tv3設置了:

app:layout_constraintLeft_toRightOf="@id/tv1"
app:layout_constraintBottom_toBottomOf="@id/tv1"

按照我們剛纔的理解,再次的解讀下:

tv1應該是在父佈局的左上角;

tv2在tv1的右側,tv2的右側和父佈局對其,tv2和tv1頂部對齊;

tv3在tv1的右側,tv3和tv1底部對其。

到這裏,大家可以看到,目前我們已經可以控制任何一個控件與其他控件間的相對位置了,以及與parent間的相對位置。

和RelativeLayout的差異

大家是不是覺得目前來看和RelativeLayout特別像?

其實還是有很明顯的區別的,我們通過一個例子來看一下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <Button
        android:id="@+id/id_btn01"
        android:layout_width="100dp"
        android:text="Btn01"
        android:layout_height="wrap_content" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/id_btn01"
        android:text="Btn02"
        android:layout_alignParentRight="true"
        />
</RelativeLayout>

那麼經過我們剛纔的學習,把:

layout_toRightOf="@id/id_btn01"
layout_alignParentRight="true"

分別替換爲:

app:layout_constraintLeft_toRightOf="@id/id_btn01"
app:layout_constraintRight_toRightOf="parent"

是不是覺得so easy ,但是我們看一下效果圖:


是不是和預期有一定的區別,假設你將Btn02的寬度設置的非常大,你會發現更加詭異的事情:


你會發現Btn02,好像瘋了一樣,我們設置的在btn01右側,和與parent右側對齊完全失效了!!!

別怕,接下來就讓你認識到爲什麼這個控件叫做“Constraint”Layout。

在當控件有自己設置的寬度,例如warp_content、固定值時,我們爲控件添加的都是約束“Constraint”,這個約束有點像橡皮筋一樣會拉這個控件,但是並不會改變控件的尺寸(RL很明顯不是這樣的)。

例如上例,當btn02的寬度較小時,我們爲其左側設置了一個約束(btn01右側),右側設置了一個約束(parent右側對其),當兩個約束同時生效的時候(你可以認爲兩邊都是相同的一個拉力),btn02會居中。

當btn02特別大的時候,依然是這兩個力,那麼會發生什麼?會造成左側和右側超出的距離一樣大。

那麼現在大家肯定有些疑問:

  • 怎麼樣才能和上面的RL一樣,寬度剛好佔據剩下的距離呢(btn01右側到屏幕右側的距離)?
    這個問題,問得很好,我們剛纔所有的嘗試都是在控件自身擁有特定的寬度情況下執行的;那麼如果希望控件的寬度根據由約束來控件,不妨去掉這個特定的寬度,即設置爲0試試?

對!當我們將btn02的寬度設置爲0時,一切又變得很完美。


那麼這裏,你可能會問0值是什麼含義,其實在ConstraintLayout中0代表:MATCH_CONSTRAINT,看到這個常量,是不是瞬間覺得好理解了一點。

  • 最後一個問題,MATCH_PARENT哪去了?

看官網的解釋:
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中已經不支持MATCH_PARENT這個值了,你可以通過MATCH_CONSTRAINT配合約束實現類似的效果。

好了,到這裏,目前我們已經看到其已經和RelativeLayout勢均力敵了,接下來我們看一下RL做不到的特性。

增加一個banner

我們現在以往在這個feed item頂部添加一個banner,寬度爲佔據整個屏幕,寬高比爲16:6。

這裏尷尬了,在之前的做法,很難在佈局中設置寬高比,一般我們都需要在代碼中顯示的去操作,那麼如果你用了ConstraintLayout,它就支持。

看一眼如何支持:

<android.support.constraint.ConstraintLayout 
    ...
    tools:context="com.zhy.constrantlayout_learn.MainActivity">

    <TextView
        android:id="@+id/banner"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#765"
        android:gravity="center"
        android:text="Banner"
        app:layout_constraintDimensionRatio="H,16:6"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />


    <TextView
        android:id="@+id/tv1"
        app:layout_constraintTop_toBottomOf="@id/banner"
        ></TextView>
     ...
</...>

我們添加了一個banner,還記得我們剛纔所說的麼,不要使用match_parent了,而是設置match_contraint,即0,讓約束來控制佈局寬高。

所以我們設置了寬、高都是match_contraint,然後這兩個屬性:

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

讓我們的寬度充滿整個父佈局,在添加一個:

app:layout_constraintDimensionRatio="16:6"

該屬性指的是寬高比,所以16:6就可以完成我們的需求。

好了看下效果圖:


這個寬高比屬性,還支持這樣的寫法:

app:layout_constraintDimensionRatio="W,16:6"
app:layout_constraintDimensionRatio="H,16:6"

可以自己試驗下。

好了,到這裏,我們又新增了一個屬性,還是個非常實用的屬性。

那麼,我們繼續,再看一個似曾相識的功能。

增加幾個Tab

現在我們希望在底部增加3個tab,均分。是不是想到了LinearLayout和weight。

沒錯!ConstraintLayout也支持類似的屬性。

雖然我知道,但是寫到這我還是有點小驚喜~~

看下如何實現:

<TextView
    android:id="@+id/tab1"
    android:layout_width="0dp"
    android:layout_height="30dp"
    android:background="#f67"
    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="30dp"
    android:background="#A67"
    android:gravity="center"
    android:text="Tab2"
    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="30dp"
    android:background="#767"
    android:gravity="center"
    android:text="Tab3"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toRightOf="@id/tab2"
    app:layout_constraintRight_toRightOf="parent" />

我們增加3個textview來冒充tab。我們看橫向的依賴,3個tab兩兩設置了約束(即你在我們的左邊,我在你的右邊),最外層的設置了parent約束;再加上我們把寬度都設置爲了match_constraint,so,這樣我們就完成了3個tab等分。

看一眼效果圖:


你可能會說,LL配合weight更加靈活,可以單個設置佔據的比例。

對,沒錯,我們也支持,我不是還沒說完麼。

現在我們可以給每個tab設置一個屬性:

app:layout_constraintHorizontal_weight

看到這個名字,應該就明白了吧,假設我們分別設置值爲2,1,1。

效果圖爲:


是不是很驚喜,別急,剛纔你說我不如LL,現在我要讓你再看一些LL配合weight做不到的。

這裏需要藉助幾張官網上的圖了:

剛纔我們說了,3個tab兩兩設置了依賴,即類似下圖:


橫向的相當於組成了一個鏈(Chains)。在這個鏈的最左側的元素成爲鏈頭,我們可以在其身上設置一些屬性,來決定這個鏈的展示效果:

該屬性爲:

layout_constraintHorizontal_chainStyle

我們已經見過一種效果了,即按照weight等分,可以成爲weighted chain。設置條件爲:

chainStyle=”spread”,所有控件寬度設置爲match_constraint,因爲默認就是spread,所以我們沒有顯示設置。

其取值還可以爲:

  • packed
  • spread_inside
    我還是分別顯示一下吧:

1.spread + 寬度非0


1.spread + 寬度爲0,且可以通過weight控制分配比例(上例)

2.spread_inside + 寬度非0


1.packed + 寬度非0


好了,差不多了,我們可以在橫向或者縱向組成一個Chain,然後在Chain head設置chainStyle來搞一些事情。

官網有個圖:


前四個我們都演示了,最後一個設計到一個新的bias屬性,別急,咱們慢慢說~~

好了,到這裏,我們再次見證了ConstraintLayout的強大。

我們最後再看一個例子。

增加浮動按鈕

一個很常見的功能,我們現在希望在右下角增加一個浮動按鈕。

看下如何實現:

<android.support.constraint.ConstraintLayout 
    ...
    tools:context="com.zhy.constrantlayout_learn.MainActivity">

    <TextView
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="#612"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.9"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.9" />
</....>

我們在最後追加一個TextView冒充我們的浮動按鈕。可以看到我們設置了固定值,被設置約束爲右下角。

正常情況我們可以通過margin來設置與右側與底部的距離。

但是這裏我們嘗試使用量個新的屬性:

layout_constraintHorizontal_bias
layout_constraintVertical_bias

即設置上下兩側間隙比例分別爲90%與10%。這個很好理解,我們之前說了,再沒有bias這個屬性的時候,這兩側的拉力大小是一樣的,但是你可以通過bias來控制哪一側的力要大一些~明白了麼

所以,該屬性可以用於約束之前,控制兩側的“拉力”。

我們看一下效果圖:


那麼到這裏,ConstraintLayout的屬性我們基本上介紹完了:

我們看一下:

layout_constraintLeft_toLeftOf 
layout_constraintLeft_toRightOf
layout_constraintRight_toLeftOf
layout_constraintRight_toRightOf
layout_constraintTop_toTopOf
layout_constraintTop_toBottomOf
layout_constraintBottom_toTopOf
layout_constraintBottom_toBottomOf

# 即文章的baseline對齊
layout_constraintBaseline_toBaselineOf

# 與left,right類似
layout_constraintStart_toEndOf 
layout_constraintStart_toStartOf
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf

# margin不需要解釋
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom

layout_constraintHorizontal_bias  
layout_constraintVertical_bias  

layout_constraintHorizontal_chainStyle
layout_constraintVertical_chainStyle

layout_constraintVertical_weight

Guideline 

好像,還有個比較特殊的,叫Guideline。

好吧,繼續~

嘗試使用Guideline

android.support.constraint.Guideline該類比較簡單,主要用於輔助佈局,即類似爲輔助線,橫向的、縱向的。該佈局是不會顯示到界面上的。

所以其有個屬性爲:

android:orientation取值爲”vertical”和”horizontal”.

除此以外,還差個屬性,決定該輔助線的位置:

  • layout_constraintGuide_begin
  • layout_constraintGuide_end
  • layout_constraintGuide_percent
    可以通過上面3個屬性其中之一來確定屬性值位置。

begin=30dp,即可認爲距離頂部30dp的地方有個輔助線,根據orientation來決定是橫向還是縱向。

end=30dp,即爲距離底部。
percent=0.8即爲距離頂部80%。

好了,下面看一個例子,剛纔我們的浮點按鈕,我決定通過兩根輔助線來定位,一根橫向距離底部80%,一個縱向距離頂部80%,浮點按鈕就定位在他們交叉的地方。

<android.support.constraint.ConstraintLayout 
    ...
    tools:context="com.zhy.constrantlayout_learn.MainActivity">

    <android.support.constraint.Guideline
        android:id="@+id/guideline_h"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.8" />


    <android.support.constraint.Guideline
        android:id="@+id/guideline_w"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.8" />

    <TextView
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="#612"
        app:layout_constraintLeft_toRightOf="@id/guideline_w"
        app:layout_constraintTop_toBottomOf="@id/guideline_h" />
</....>

我感覺都不用解釋了~~看眼效果圖吧:


到此,屬性基本上講完啦~

可以看到,上述相當複雜的一個佈局,在ConstraintLayout中完全沒有嵌套!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章