ConstraintLayout 用法全解析

*本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布

本文是基于constraint-layout:1.1.2

一、前言

在以前,android是使用布局如LinearLayout 、RelativeLayout等來構(gòu)建頁(yè)面,但這些布局使用起來很麻煩,并且經(jīng)常需要一層一層嵌套,寫一個(gè)簡(jiǎn)單的頁(yè)面就需要費(fèi)很大的勁。所以在16年I/O大會(huì)上,google發(fā)布了全新的布局-ConstraintLayout,其他布局和ConstraintLayout比起來,根本就沒有存在的必要了...
ConstraintLayout具有以下優(yōu)勢(shì):

  1. 較高的性能優(yōu)勢(shì)。
    布局嵌套層次越高,性能開銷越大。而使用ConstraintLayout,經(jīng)常就一層嵌套就搞定了,所以其性能要好很多。
    詳細(xì)的性能分析可參見:解析ConstraintLayout的性能優(yōu)勢(shì)

  2. 完美的屏幕適配
    ConstraintLayout的大小、距離都可以使用比例來設(shè)置,所以其適配性更好。

  3. 書寫簡(jiǎn)單

  4. 可視化編輯。
    ConstraintLayout也有十分方便完善的可視化編輯器,不用寫xml也基本上能實(shí)現(xiàn)大部分功能。但個(gè)人還是比較喜歡寫xml,所以本篇文章主要介紹如何使用代碼控制。如果想看如何使用可視化編輯器,可以參考郭霖大神的這篇文章

引入:api 'com.android.support.constraint:constraint-layout:1.1.2'

二、ConstraintLayout

1. 定位位置

確定位置的屬性提供了下面13個(gè)屬性,其實(shí)本質(zhì)上都是一樣的,看名字應(yīng)該基本上都知道怎么用了(就是哪一條邊和哪一條邊對(duì)齊)

  • layout_constraintLeft_toLeftOf
  • layout_constraintLeft_toRightOf
  • layout_constraintRight_toLeftOf
  • layout_constraintRight_toRightOf
  • layout_constraintTop_toTopOf
  • layout_constraintTop_toBottomOf
  • layout_constraintBottom_toTopOf
  • layout_constraintBottom_toBottomOf
  • layout_constraintBaseline_toBaselineOf
  • layout_constraintStart_toEndOf
  • layout_constraintStart_toStartOf
  • layout_constraintEnd_toStartOf
  • layout_constraintEnd_toEndOf

來看個(gè)例子:


實(shí)現(xiàn)上述UI的相關(guān)代碼如下:

<android.support.constraint.ConstraintLayout 
    ...>

    <Button
        android:id="@+id/a"
         ....
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="A" />

    <Button
        android:id="@+id/b"
        ....
        app:layout_constraintLeft_toRightOf="@id/a"
        app:layout_constraintTop_toTopOf="@id/a"
        android:text="B" />

    <Button
        android:id="@+id/c"
         ....
        app:layout_constraintLeft_toLeftOf="@id/a"
        app:layout_constraintTop_toBottomOf="@id/a"
        android:text="C" />

    <Button
        android:id="@+id/d"
         ....
        app:layout_constraintLeft_toRightOf="@id/a"
        app:layout_constraintTop_toTopOf="@id/c"
        android:text="D" />
</android.support.constraint.ConstraintLayout>

從中可以看到,

  • layout_constraint*屬性的值可以是某個(gè)id或者parent(父布局)
  • B要位于A的右邊,則使用app:layout_constraintLeft_toRightOf="@id/a",C位于A的下邊,則使用app:layout_constraintTop_toBottomOf="@id/a"

對(duì)于一個(gè)View的邊界界定,官方給了下面這張圖:


2. margin

設(shè)置margin還是繼續(xù)用以前的屬性layout_margin*
不過需要注意,要使margin生效,必須具有對(duì)應(yīng)方向的layout_constraint*,否則margin不生效.

3. 關(guān)于view gone

假如現(xiàn)在有如下布局:


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    ...>

    <Button
        android:id="@+id/a"
        ...
        android:layout_marginLeft="100dp"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/b"
        ...
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toRightOf="@id/a"
        app:layout_constraintTop_toTopOf="@id/a"
         />

    <Button
        android:id="@+id/c"
       ....
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        app:layout_constraintLeft_toRightOf="@id/b"
        app:layout_constraintTop_toTopOf="@id/b" />
</android.support.constraint.ConstraintLayout>

考慮一個(gè)問題,如果B動(dòng)態(tài)設(shè)為gone了,C會(huì)怎么顯示呢?
真實(shí)情況如下:



為什么會(huì)這樣顯示呢?看他的藍(lán)圖應(yīng)該會(huì)好理解些:



可以看出,b設(shè)為gone之后,他的寬、高、margin都失效了,變?yōu)橐粋€(gè)點(diǎn)了,但它的constrain還生效,位于指定的位置。c還是可以繼續(xù)以他為錨點(diǎn)。
那么如何解決關(guān)于View gone引起的非預(yù)期的布局變化呢?
  1. 如果可以,盡量使用invisible
  2. 盡量其他view的布局不依賴會(huì)gone的view
  3. google也提供了屬性layout_goneMargin*="xdp",意思是比如當(dāng)constrainleft的錨點(diǎn)gone時(shí),layout_goneMarginLeft將生效。但因?yàn)檫@個(gè)只能設(shè)置固定的距離,個(gè)人感覺靈活性不是很高。

4. 居中及bias

一個(gè)view如何設(shè)置為居中呢?如果查找屬性,會(huì)發(fā)現(xiàn)并沒有如RelativeLayout類似的layout_centerVertical屬性,那如何設(shè)置居中呢?constraint的思想很巧妙。
根據(jù)第一節(jié)的知識(shí),大家知道如果設(shè)置app:layout_constraintLeft_toLeftOf="parent",則view會(huì)貼著父view的左邊,設(shè)置app:layout_constraintRight_toRightOf="parent" 則會(huì)貼著右邊,那如果兩個(gè)都設(shè)置,效果會(huì)怎樣呢?


如圖,兩個(gè)都設(shè)置,view則會(huì)居中。
至此可以看出,對(duì)constraint的理解其實(shí)可以看成是像兩個(gè)彈簧一樣,如果只在左邊加一個(gè)彈簧,右邊沒有,那左邊的勢(shì)必會(huì)把view拉到左邊去,如果在右邊也加一根彈簧,兩個(gè)彈簧力相互平衡,則view就居中了。
上面是view居中,如果我想讓view向左偏一些,或者位于1/3處該怎么處理?其實(shí)也是一樣的,想象一下,如果左邊的彈簧力大一些,view不是就自然往左偏了嘛。如何使力大一些呢?使用如下屬性

  • layout_constraintHorizontal_bias
  • layout_constraintVertical_bias

bias即偏移量,他們的取值范圍從0~1,0即挨著左邊,1是挨著右邊,所以要使處于1/3處,可以設(shè)置如下屬性app:layout_constraintHorizontal_bias="0.33",效果圖如下:

5.view的尺寸

設(shè)置view的大小除了傳統(tǒng)的wrap_content、指定尺寸、match_parent(雖然官方不推薦使用match_parent)外,還可以設(shè)置為0dp(官方取名叫MATCH_CONSTRAINT),0dp在constraint可不是指大小是0dp,而是有特殊含義的。他的作用會(huì)隨著不同的設(shè)置有不同的含義:

  1. layout_constraintWidth_default
    layout_constraintWidth_default有三個(gè)取值,作用如下:
  • spread,默認(rèn)值,意思是占用所有的符合約束的空間
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
  ...>

    <Button
        android:id="@+id/a"
        android:layout_width="0dp"
        ...
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

</android.support.constraint.ConstraintLayout>

可以看到layout_width為0dp,實(shí)際的效果則是寬度和約束一樣,左右兩邊的留白是margin的效果。

  • percent,意思是按照父布局的百分比設(shè)置,需要layout_constraintWidth_percent設(shè)置百分比例
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout >

    <android.support.constraint.ConstraintLayout
        android:layout_width="300dp"
        android:layout_height="400dp"
        app:layout_constraintHorizontal_bias="0.3"
        >

        <Button
            android:id="@+id/a"
            android:layout_width="0dp"
            ...
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintWidth_default="percent"
            app:layout_constraintWidth_percent="0.4" />
    </android.support.constraint.ConstraintLayout>

</android.support.constraint.ConstraintLayout>

A的寬度設(shè)為0.4,則其寬度為父布局的0.4倍。另外,設(shè)置了layout_constraintWidth_percent屬性,可以不用指定layout_constraintWidth_default,他會(huì)自動(dòng)設(shè)置為percent

  • wrap,意思匹配內(nèi)容大小但不超過約束限制,注意和直接指定寬度為wrap_content的區(qū)別就是不超過約束限制,如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    ...>


    <Button
        android:id="@+id/a"
        ...
        app:layout_constraintLeft_toLeftOf="parent" />
    <Button
        android:id="@+id/c"
        ...
        app:layout_constraintRight_toRightOf="parent" />

    <Button
        android:id="@+id/b"
        android:layout_width="0dp"
         ...
        app:layout_constraintWidth_default="wrap"
        app:layout_constraintLeft_toRightOf="@id/a"
        app:layout_constraintRight_toLeftOf="@id/c"/>

    <Button
        android:id="@+id/d"
        android:layout_width="wrap_content"
        ...
        app:layout_constraintTop_toBottomOf="@id/b"
        app:layout_constraintLeft_toRightOf="@id/a"
        app:layout_constraintRight_toLeftOf="@id/c"/>

</android.support.constraint.ConstraintLayout>

可以看到雖然文字很長(zhǎng),但第一行的綠色button寬度達(dá)到約束時(shí),就不在增加,而第二行的button顯示了完整的內(nèi)容,超過約束的限制。
在1.1上 對(duì)于wrap_content會(huì)超過約束限制,谷歌又新增了如下屬性

  • app:layout_constrainedWidth=”true|false”
  • app:layout_constrainedHeight=”true|false”

設(shè)置為true也可以限制內(nèi)容不超過約束(這樣感覺layout_constraintWidth_default這個(gè)屬性已經(jīng)沒什么用了)

  1. ratio
    layout_constraintDimensionRatio,即寬和高成一定的比例,其值可以是"width:height"的形式,也可以是width/height的值。該屬性生效的前提:寬和高其中有一項(xiàng)為0dp,有constraint。下面按照有幾個(gè)0dp來分別介紹下:
  • 如果只有一項(xiàng)為0dp,則該項(xiàng)值按照比例計(jì)算出來。比如高為20dp,寬為0dp,radio為"2:1",則最終寬為40dp
  • 如果兩項(xiàng)都為0dp,則尺寸會(huì)設(shè)置為滿足約束的最大值并保持比例。因?yàn)檫@是系統(tǒng)計(jì)算的,有的時(shí)候不是我們想要的,我們也可以通過在前面加H、W來指定是哪一個(gè)邊需要計(jì)算。例如"H,2:1",則是指寬度匹配約束,高度是寬度的1/2
  1. max min
    有如下屬性可以設(shè)置其的最大最小值,含義如字面值一樣:
  • layout_constraintWidth_min
  • layout_constraintWidth_max
  • layout_constraintHeight_max
  • layout_constraintHeight_min
  1. weight
    該屬性在下面講解

6. 鏈

如圖,在一個(gè)水平或者豎直方向上,一排view兩兩互相約束,即為鏈


鏈的第一個(gè)元素稱為鏈頭,可以通過設(shè)置layout_constraintHorizontal_chainStyle來控制鏈的分布形式

  • spread
    默認(rèn)模式,分布樣式如上圖

  • spread_inside
    如圖,和spread的區(qū)別是沒算兩端的約束


  • packed
    所有元素?cái)D在中間,也可以配合使用bias來改變位置偏移


可以看出,鏈與LinearLayout效果大致一樣。和LinearLayout一樣,鏈也可以使用layout_constraintHorizontal_weight,來分割剩余空間。但又和 android:layout_weight不太一樣,不一樣的地方如下:

  • layout_weight ,不管當(dāng)前view的大小設(shè)的是多大,都會(huì)繼續(xù)占據(jù)剩余空間
  • layout_constraintHorizontal_weight,這個(gè)只對(duì)0dp并且layout_constraintWidth_default為spread的view生效,使其大小按比例分割剩余空間,對(duì)于已經(jīng)設(shè)定大小的view不生效

如下面的示例:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    ...>

    <LinearLayout
        ...
        android:orientation="horizontal">
        <Button
            android:layout_width="10dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            ... />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            android:layout_weight="1"
            ... />
        <Button
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            ... />
    </LinearLayout>

    <android.support.constraint.ConstraintLayout
        ....>

        <Button
            android:id="@+id/a"
            android:layout_width="10dp"
            android:layout_height="50dp"
            ....
            app:layout_constraintHorizontal_weight="1"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toLeftOf="@id/b" />
        <Button
            android:id="@+id/b"
            android:layout_width="wrap_content"
            android:layout_height="50dp"
            ....
            app:layout_constraintHorizontal_weight="1"
            app:layout_constraintLeft_toRightOf="@id/a"
            app:layout_constraintRight_toLeftOf="@id/c" />

        <Button
            android:id="@+id/c"
            android:layout_width="0dp"
            android:layout_height="50dp"
            ...
            app:layout_constraintHorizontal_weight="1"
            app:layout_constraintLeft_toRightOf="@id/b"
            app:layout_constraintRight_toRightOf="parent" />

        />
    </android.support.constraint.ConstraintLayout>

</LinearLayout>

可以看出,LinearLayout和ConstraintLayout雖然三個(gè)子view的layout_width值是一樣的,weight也都設(shè)置了1,但效果完全不一樣

7. 圓形布局

ConstraintLayout還提供了一種比較炫酷的圓形布局,這是以往的布局所做不到的。涉及到的屬性也很簡(jiǎn)單,就下面三個(gè):

  • layout_constraintCircle : 圓心,值是某個(gè)view的id
  • layout_constraintCircleRadius : 半徑
  • layout_constraintCircleAngle :角度,值是從0-360,0是指整上方

示例如下:


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
   ...>

   <Button
       android:id="@+id/a"
       ...
       />

   <Button
       android:id="@+id/b"
       ...
       app:layout_constraintCircle="@id/a"
       app:layout_constraintCircleAngle="300"
       app:layout_constraintCircleRadius="100dp" />

   <Button
       android:id="@+id/c"
       ...
       app:layout_constraintCircle="@id/a"
       app:layout_constraintCircleAngle="45"
       app:layout_constraintCircleRadius="200dp" />
   />
</android.support.constraint.ConstraintLayout>

三、輔助組件

除了ConstraintLayout自身屬性之外,谷歌還提供了很多輔助布局(只是在布局中起輔助作用,并不會(huì)在界面真正顯示),來使ConstraintLayout的功能更加強(qiáng)大。下面,我們就一一來了解下這些布局

1. GuideLine

即參考線的意思,有水平參考線和豎直參考線兩種。他的作用就像是一個(gè)虛擬的參考線,只是用來方便其他View以他為錨點(diǎn)來布局。
如上一篇所了解到的,ConstraintLayout 的定位原則就是一個(gè)View參考其他View的相對(duì)布局,如果有的時(shí)候當(dāng)前布局沒有合適的參考View,而建一個(gè)專門用于定位的View又會(huì)太重,這種情況正是GuideLine的用武之地。
例如:


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    ...>

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        ...
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.33" />

    <android.support.constraint.Guideline
        android:id="@+id/guideline2"
        ...
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="130dp" />

    <Button
        ...
        app:layout_constraintLeft_toLeftOf="@id/guideline"
        app:layout_constraintTop_toTopOf="@id/guideline2" />


</android.support.constraint.ConstraintLayout>

可以看到我分別添加了一個(gè)水平參考線和豎直參考線,之后的Button的布局就參考與這兩個(gè)參考線,而在布局中并不會(huì)顯示。
Guideline的大部分的屬性如layout_width都是不會(huì)生效的,而他的位置的確定是由下面三個(gè)屬性之一來確定的:

  • layout_constraintGuide_begin:距離父布局的左邊或者上邊多大距離
  • layout_constraintGuide_end:距離父布局的右邊或者下邊多大距離
  • layout_constraintGuide_percent:百分比,0~1,距離父布局的左邊或者上邊占父布局的比例

2. Group

Group是一個(gè)可以同時(shí)控制多個(gè)view 可見性的虛擬View。
例如:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
  ...>

    <android.support.constraint.Group
       ...
        android:visibility="invisible"
        app:constraint_referenced_ids="a,c" />

    <android.support.constraint.Group
        ...
        android:visibility="visible"
        app:constraint_referenced_ids="b,d" />

    <Button
        android:id="@+id/a"
        ... />

    <Button
        android:id="@+id/b"
        ... />

    <Button
        android:id="@+id/c"
       ... />

    <Button
        android:id="@+id/d"
        .../>
</android.support.constraint.ConstraintLayout>

可以看到,第一個(gè)Group通過app:constraint_referenced_ids指定了a、c兩個(gè)控件,這樣當(dāng)該Group可見性為invisible時(shí),a、c的可見性都會(huì)變?yōu)閕nvisible,為gone則都為gone。所以Group很適合處理有網(wǎng)無(wú)網(wǎng)之類的場(chǎng)景,不再需要像之前那樣一個(gè)一個(gè)view控制可見性,通過Group就可以統(tǒng)一處理了。
Group有一些注意事項(xiàng):

  • xml中,可見性配置的優(yōu)先級(jí):Group優(yōu)先于View,下層Group優(yōu)先于上層。
  • Group只可以引用當(dāng)前ConstraintLayout下的View,子Layout 下的View不可以。
  • app:constraint_referenced_ids里直接寫的是id的字符串,初始化后會(huì)通過getIdentifier來反射查找叫該名字的id。所以如果你的項(xiàng)目用了類似AndResGuard的混淆id名字的功能,切記不要混淆app:constraint_referenced_ids里的id,否則在release版本就會(huì)因找不到該id而失效。或者也可以通過代碼setReferencedIds來設(shè)置id。

3. Placeholder

占位布局。他自己本身不會(huì)繪制任何內(nèi)容,但他可以通過設(shè)置app:content="id",將id View的內(nèi)容繪制到自己的位置上,而原id的 View就像gone了一樣。
如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
...>
    <Button
        android:id="@+id/a"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="30dp"
       ...
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/b"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="20dp"
        ...
        app:layout_constraintLeft_toRightOf="@+id/a"
        app:layout_constraintTop_toTopOf="@+id/a" />

    <android.support.constraint.Placeholder
        android:id="@+id/place"
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:content="@+id/a"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"/>

    <Button
        ...
        app:layout_constraintBottom_toBottomOf="@+id/place"
        app:layout_constraintLeft_toRightOf="@+id/place" />
</android.support.constraint.ConstraintLayout>

效果如圖:


可以看到,原本B是位于A的右邊并且頂部對(duì)齊的,但因?yàn)锳被Placeholder引用,使A 相當(dāng)于Gone了。而Placeholder的位置則顯示了A的內(nèi)容,并且大小也和A相符,Placeholder的大小設(shè)置并沒有生效。
大概總結(jié)可以認(rèn)為,Placeholder引用A后的效果是,原本位置的A gone,原本位置的Placeholder變?yōu)镻laceholder的約束屬性+A的內(nèi)容屬性。另外,Placeholder也支持使用代碼setContentId動(dòng)態(tài)的修改設(shè)置內(nèi)容。

關(guān)于Placeholder的應(yīng)用場(chǎng)景,網(wǎng)上其他人也都列出了一些例子:比如可以作為位置模板,引入后只需要寫內(nèi)容view;使用代碼動(dòng)態(tài)改變內(nèi)容,結(jié)合TransitionManager可以做一些有趣的過度動(dòng)畫等。

4. Barrier

屏障,一個(gè)虛擬View。他主要解決下面遇到的問題:



如上圖布局,兩個(gè)TextView,一個(gè)button位于他們的右邊。現(xiàn)在button設(shè)置的是在下面TextView的右邊。假設(shè)有時(shí)候上面的TextView文本變長(zhǎng)了,則布局會(huì)變?yōu)橄旅孢@個(gè)樣子:



上面的TextView和Button重疊了。這時(shí)該怎么解決這個(gè)問題呢?Button只能設(shè)置一個(gè)View作為錨點(diǎn),設(shè)置了上面就顧不了下面了。。。
所以就誕生了Barrier,他可以設(shè)置N個(gè)View作為錨點(diǎn),使用方式如下:
<android.support.constraint.Barrier
              android:id="@+id/barrier"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              app:barrierDirection="end"http://end,left,right,top,bottom
              app:constraint_referenced_ids="text1,text2" />

則Barrier始終位于text1,text2兩個(gè)View最大寬度的右邊,示意圖如下:


這里基本的用法就講完了。
下面再考慮一個(gè)情況,假如有如下的布局:


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
  ...>

    <Button
        android:id="@+id/a"
        ...
        android:layout_marginTop="20dp"
         />

    <Button
        android:id="@+id/b"
        ...
        android:layout_marginTop="40dp"
         />

    <android.support.constraint.Barrier
        android:id="@+id/barrier"
        ...
        app:barrierDirection="top"
        app:constraint_referenced_ids="a,b" />

    <Button
        android:id="@+id/c"
        ...
        app:layout_constraintTop_toTopOf="@+id/barrier" />
</android.support.constraint.ConstraintLayout>

目前Button C和Button a、b的最上值對(duì)齊,沒有問題。但如果a Gone了呢?效果如下:


其實(shí)也是符合邏輯,a gone后,會(huì)變?yōu)橐粋€(gè)點(diǎn),所以C頂齊父布局也沒問題。但有的時(shí)候這不符合我們的需求,我們希望Barrier不要關(guān)注Gone的View了,所以谷歌提供了屬性barrierAllowsGoneWidgets,設(shè)為false后,就不在關(guān)注Gone的View了,效果如下:

四、結(jié)束

本篇已基本上介紹完ConstraintLayout所有的屬性了(除了代碼寫布局的ConstraintSet類)。在2018.8.9號(hào),谷歌又發(fā)布了2.0.0-alpha2版本,里面加入了許多好玩的新特性,相信ConstraintLayout之后會(huì)越來越強(qiáng)大。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評(píng)論 1 295
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評(píng)論 2 380

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