ConstraintLayout,讓佈局更優雅。html
上圖是網易100分的選課首頁,在Banner圖的下部是推薦類目模塊,其中數學、語言、小低和小高分別是推薦類目Item。可見每一個類目的子類目個數是不肯定的,根據個數的不一樣,子類目的排列方式也不同。android
如今咱們來實現Item的佈局。若是用LinearLayout、RelativeLayout和FrameLayout去實現Item佈局,我目前想到的最低也須要兩層佈局。以下所示:git
<Relative>
<ImageView />
<TextView />
<LinearLayout>
<TextView />
<TextView />
<TextView />
</LinearLayout>
<LinearLayout>
<TextView />
<TextView />
</LinearLayout>
</Relative>
複製代碼
能夠發現沒有一種佈局容器是能夠單靠本身搞定這個佈局的,須要嵌套不一樣佈局。這樣佈局層級增長,佈局計算時間也加長了。這些都是傳統佈局存在的問題,歸納起來有如下三點:github
正是因爲目前佈局容器存在的問題,咱們須要尋找一種能夠解決這些問題的佈局容器。正好,ConstraintLayout能夠。編程
ConstraintLayout,中文稱約束佈局,在2016年Google I/O大會時提出,2017年2月發佈正式版,目前穩定版本爲1.0.2。約束佈局做爲Google從此主推的佈局樣式,能夠徹底替代其餘佈局,下降頁面佈局層級,提高頁面渲染性能。bash
ConstraintLayout支持最低Android Studio版本是2.2,可是有些屬性在2.2的佈局編輯器上不支持編輯,如比例和baseline等約束。因此推薦使用2.3的版本,固然3.0的版本那就更好了。要使用ConstraintLayout,須要在項目中進行以下配置:app
repositories {
maven {
url 'https://maven.google.com'
}
}
複製代碼
dependencies {
compile 'com.android.support.constraint:constraint-layout:1.0.2'
}
複製代碼
按照上述配置好環境後,咱們就能夠在項目中使用ConstraintLayout了。有兩種方式使用:maven
layout轉換的方式使用編輯器
首先,打開一個非ConstraintLayout的佈局文件,切換到Design Tab
ide
在Component Tree窗口,選中要轉換的layout文件根佈局,點擊右鍵,而後選擇Convert layout to ConstraintLayout
直接新建一個layout文件使用
經過以下方式引入約束佈局:
<android.support.constraint.ConstraintLayout
/>
複製代碼
ConstraintLayout的佈局屬性,乍一看有不少,其實能夠分爲8個部分,下面一一介紹。
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
複製代碼
以上這些屬性,用於設置一個控件相對於其餘控件、Guideline或者父容器的位置。以layout_constraintLeft_toLeftOf
爲例,其中layout_
部分是固定格式,主要的信息包含在下面兩部分:
constraintLeft
表示對當前控件的左邊進行約束設置。XXX
指定被依賴對象用於參考的屬性。如toLeftOf="parent"
:表示當前控件相對於父容器的左邊進行約束設置。ConstraintLayout的相對位置佈局比較靈活,相比於RelativeLayout,ConstraintLayout能夠經過layout_constraintBaseline_toBaselineOf
設置兩個控件之間的文字相對於baseline對齊。一個佈局效果的例子,以下所示:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_relative_position"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.RelativePositionActivity">
<Button
android:id="@+id/btn_A"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<Button
android:text="在A下方,與A左對齊"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="@id/btn_A"
android:layout_marginTop="32dp"
/>
<Button
android:text="在A上方,與A居中對齊"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="@id/btn_A"
app:layout_constraintRight_toRightOf="@id/btn_A"
android:layout_marginBottom="32dp"
/>
<Button
android:text="baseline對齊"
android:layout_width="wrap_content"
android:layout_height="80dp"
app:layout_constraintBaseline_toBaselineOf="@id/btn_A"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginLeft="8dp"
android:gravity="bottom"
/>
<Button
android:text="水平居中對齊"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:gravity="bottom"
app:layout_constraintTop_toTopOf="@id/btn_A"
app:layout_constraintBottom_toBottomOf="@id/btn_A"
app:layout_constraintLeft_toRightOf="@id/btn_A"
android:layout_marginLeft="16dp"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
在ConstraintLayout中,控件除了能夠設置普通的邊距屬性,還能夠設置當控件依賴的控件GONE以後的邊距屬性。即咱們能夠理解能夠根據被依賴控件是否GONE的狀態,設置兩種邊距值。分別經過以下屬性進行設置:
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
複製代碼
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
複製代碼
這種特性,能夠比較方便實現一些特定的需求,且無需代碼中進行額外設置。如B控件依賴A,A距離父容器左邊20dp,B在A右邊,距離A爲20dp。需求當A設置爲GONE以後,B距離父容器左邊60dp。這在ConstraintLayout中實現起來就很簡單,對B同時設置以下屬性便可:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_margin"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.MarginActivity">
<Button
android:id="@+id/btn_a"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="100dp"
/>
<Button
android:text="B"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@id/btn_a"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginLeft="20dp"
app:layout_goneMarginLeft="60dp"
android:layout_marginTop="100dp"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent 複製代碼
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
複製代碼
例子:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_center_position"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.CenterPositionActivity">
<Button
android:text="水平居中"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:text="垂直居中"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
<Button
android:text="水平垂直居中"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
在設置控件的居中屬性以後,經過偏移屬性能夠設置讓控件更偏向於依賴控件的某一方,偏移設置爲0~1之間的值。相應屬性:
layout_constraintHorizontal_bias // 水平偏移
layout_constraintVertical_bias // 垂直偏移
複製代碼
例子:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_bias"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.BiasActivity">
<Button
android:text="水平偏移30%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3"
/>
<Button
android:text="垂直偏移30%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.3"
/>
<Button
android:text="水平垂直偏移70%"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.7"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.7"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
可見性這個屬性你們應該很熟悉,可是約束佈局的可見性屬性和其它佈局相比,存在如下區別:
當控件設爲GONE時,被認爲尺寸爲0。能夠理解爲佈局上的一個點。
若GONE的控件對其它控件有約束,則約束保留並生效,但全部的邊距(margin)會清零。
wrap_content
,根據內容計算合適大小match_parent
,填充滿父佈局,此時設置的約束都不生效了。(早以前的約束佈局版本貌似不容許在其子view中使用match_parent屬性,可是我寫文章的時候發現也是能夠用上去的)layout_constraintWidth_min
和layout_constraintHeight_min
:設置最小值
layout_constraintWidth_max
和layout_constraintHeight_max
:設置最大值
layout_constraintWidth_percent
和layout_constraintHeight_percent
:設置控件相對於父容器的百分比大小(1.1.0開始支持)。使用以前須要先設置爲百分比模式,而後設置設置寬高值爲0~1之間。
設置爲百分比模式的屬性:
複製代碼
app:layout_constraintWidth_default="percent" app:layout_constraintHeight_default="percent" ```
app:layout_constrainedWidth=」true|false」
app:layout_constrainedHeight=」true|false」
複製代碼
看個具體例子:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_dimen"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.DimenActivity">
<Button
android:id="@+id/btn_1"
android:text="minWidth設置爲200dp"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:minWidth="200dp"
/>
<Button
android:id="@+id/btn_2"
android:text="設置爲MATCH_CONSTRAINT"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:id="@+id/btn_3"
android:textAllCaps="false"
android:text="layout_constrainedWidth開啓"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constrainedWidth="true"
app:layout_constraintWidth_min="300dp"
/>
<Button
android:id="@+id/btn_4"
android:textAllCaps="false"
android:text="layout_constrainedWidth關閉"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btn_3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_min="300dp"
/>
<Button
android:id="@+id/btn_5"
android:textAllCaps="false"
android:text="寬50%高30%佈局"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/btn_4"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintHeight_default="percent"
app:layout_constraintWidth_percent="0.5"
app:layout_constraintHeight_percent="0.3"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
控件能夠定義兩個尺寸之間的比例,目前支持寬高比。 前提條件是至少有一個尺寸設置爲0dp,而後經過layout_constraintDimentionRatio
屬性設置寬高比。設置方式有如下幾種:
若是寬高都設置爲0dp,也能夠用ratio設置。這種狀況下控件會在知足比例 約束的條件下,儘量填滿父佈局。
下面看個例子:
<?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"
tools:context="zr.com.constraintdemo.normal.RatioActivity">
<Button
android:id="@+id/btn_1"
android:text="寬高比設置爲2:1"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<Button
android:id="@+id/btn_2"
android:text="寬高都設置爲0dp,高寬比是16:9"
android:textAllCaps="false"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintTop_toBottomOf="@id/btn_1" />
</android.support.constraint.ConstraintLayout>
複製代碼
鏈這個概念是約束佈局新提出的,它提供了在一個維度(水平或者垂直),管理一組控件的方式。
多個view在同一個方向上雙向引用。以下圖所示:水平方向A、B、C,A位於B左邊,B位於A右邊,他們就是一對雙向引用。同理B和C也是。
雙向引用佈局代碼以下所示。A經過app:layout_constraintRight_toLeftOf="@+id/btn_2"
引用右邊的B,B經過app:layout_constraintLeft_toRightOf="@+id/btn_1"
引用A。
<Button
android:id="@+id/btn_1"
android:text="A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
/>
<Button
android:id="@+id/btn_2"
android:text="B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/tv_spread"
app:layout_constraintLeft_toRightOf="@+id/btn_1"
app:layout_constraintRight_toLeftOf="@+id/btn_3"
/>
...
複製代碼
最左邊或最上面的控件,鏈的屬性由鏈頭控制。
經過layout_constraintHorizontal_chainStyle
和layout_constraintVertical_chainStyle
在鏈的第一個元素上設置。默認spread樣式。如上所示,A做爲鏈頭,設置了chainStyle:app:layout_constraintHorizontal_chainStyle="spread_inside"
。
幾種鏈的樣式以下圖所示:
鏈的佈局代碼比較多,你們能夠看demo。主要是經過修改鏈頭的chainStyle樣式改變鏈的類型。
能夠理解爲佈局輔助線,用於佈局輔助,不在設備上顯示。
有垂直和水平兩個方向(android:orientation=「vertical/horizontal」)
有三种放置Guideline的方式:
layout_constraintGuide_begin
)layout_constraintGuide_end
)layout_constraintGuide_percent
)看例子:
<?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:id="@+id/activity_guideline"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="zr.com.constraintdemo.GuidelineActivity">
<!-- 垂直Guideline -->
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline"
app:layout_constraintGuide_percent="0.5"
android:orientation="vertical"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:text="GuideLine左邊"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_1"
app:layout_constraintRight_toLeftOf="@+id/guideline"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:text="GuideLine右邊"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_2"
app:layout_constraintLeft_toRightOf="@+id/guideline"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent"
/>
<!-- 水平Guideline -->
<android.support.constraint.Guideline
android:id="@+id/h_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintGuide_begin="200dp"
/>
<Button
android:text="Guideline上面"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@id/h_guideline"
app:layout_constraintLeft_toLeftOf="parent"
/>
<Button
android:text="Guideline下面"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/h_guideline"
app:layout_constraintLeft_toLeftOf="parent"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
經過ConstraintSet,容許在代碼中進行約束設置,進行佈局變換。(API 19及以上支持trasmition動畫)
建立ConstraintSet對象的幾種方式:
c = new ConstraintSet();
c.connect(....);
複製代碼
c.clone(context, R.layout.layout1);
複製代碼
c.clone(clayout);
複製代碼
佈局變化開啓平滑動畫的方式:
TransitionManager.beginDelayedTransition(constraintLayout);
複製代碼
其中參數constraintLayout表示動畫做用的約束佈局對象。
看個例子:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 4.4以上開啓佈局切換動畫
TransitionManager.beginDelayedTransition(constraintLayout);
// 清空margin
applyConstraintSet.setMargin(R.id.btn_1, ConstraintSet.START, 0);
applyConstraintSet.setMargin(R.id.btn_1, ConstraintSet.END, 0);
applyConstraintSet.setMargin(R.id.btn_2, ConstraintSet.START, 0);
applyConstraintSet.setMargin(R.id.btn_2, ConstraintSet.END, 0);
applyConstraintSet.setMargin(R.id.btn_3, ConstraintSet.START, 0);
applyConstraintSet.setMargin(R.id.btn_3, ConstraintSet.END, 0);
// 所有相對於父容器居中
applyConstraintSet.centerHorizontally(R.id.btn_1, R.id.activity_constraint_set);
applyConstraintSet.centerHorizontally(R.id.btn_2, R.id.activity_constraint_set);
applyConstraintSet.centerHorizontally(R.id.btn_3, R.id.activity_constraint_set);
applyConstraintSet.applyTo(constraintLayout);
}
複製代碼
看下在4.4系統以上動畫的一個效果:
更多ConstraintSet例子,推薦看這篇文章
說了這麼多,那麼約束佈局用起來到底怎麼樣呢?下面咱們來實踐下:
咱們先來分析下類目Item,能夠將類目Item分爲兩個部分:父類目和子類目兩部分。父類目包括圖片icon和文字描述。子類目包含根據個數佈局可變的按鈕。很明顯,父類目經過約束佈局的相對位置約束設置能夠實現。子類目中的子控件,能夠以父佈局中的某個控件和子類目中其餘子控件爲參照物(依賴參照對象)實現佈局。總共放置兩排的按鈕,第一排3個,第二排2個,寬度設置爲MATH_CONSTRAINT。而後在代碼中根據子類目的個數,設置相應按鈕的可見性便可實現Item根據子類目個數展現不一樣佈局的效果。
佈局XML:
<?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:paddingTop="7.5dp"
android:paddingBottom="7.5dp"
android:paddingLeft="12.5dp"
android:paddingRight="12.5dp"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginLeft="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@mipmap/ic_launcher"
/>
<TextView
android:id="@+id/tv_parent_category_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="少兒編程"
android:textSize="15sp"
android:textColor="#333333"
app:layout_constraintBottom_toBottomOf="@id/img_icon"
app:layout_constraintLeft_toRightOf="@id/img_icon"
app:layout_constraintTop_toTopOf="@id/img_icon" />
<!-- 子類目佈局開始 -->
<Button
android:id="@+id/btn_one"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:text="A"
app:layout_constraintTop_toBottomOf="@id/img_icon"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_two" />
<Button
android:id="@+id/btn_two"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="B"
app:layout_constraintLeft_toRightOf="@id/btn_one"
app:layout_constraintRight_toLeftOf="@+id/btn_three"
app:layout_constraintTop_toTopOf="@id/btn_one" />
<Button
android:id="@+id/btn_three"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="C"
app:layout_constraintLeft_toRightOf="@id/btn_two"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/btn_two" />
<!-- 第二排 -->
<Button
android:id="@+id/btn_four"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="10dp"
android:text="D"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_five"
app:layout_constraintTop_toBottomOf="@id/btn_one" />
<Button
android:id="@+id/btn_five"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="E"
app:layout_constraintLeft_toRightOf="@+id/btn_four"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/btn_four" />
</android.support.constraint.ConstraintLayout>
複製代碼
實現效果:
要求:圖片寬高比16:9,圖片寬度固定110dp。
分析:寬高比16:9,須要比例佈局;其餘都是一些位置關係,用約束佈局相對位置的一些約束能夠實現。
具體實現:
佈局XML:
<?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="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="12dp">
<ImageView
android:id="@+id/iv_course"
android:layout_width="110dp"
android:layout_height="0dp"
android:scaleType="fitXY"
android:src="@mipmap/test"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_course_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="15dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#333333"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/iv_course"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_course"
tools:text="六年級單元過關檢測六年級單元過關檢測六年級單元過關檢測" />
<TextView
android:id="@+id/tv_signature"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#666666"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="@id/tv_course_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_course_name"
tools:text="簽名" />
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_marginTop="5dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#666666"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="@id/tv_course_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_signature"
tools:text="內容內容內容內容內容內容內容內容內容內容" />
<TextView
android:id="@+id/tv_current_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:maxLines="1"
android:textColor="#f6454a"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="@id/tv_course_name"
app:layout_constraintTop_toBottomOf="@id/tv_content"
tools:text="¥ 480" />
<TextView
android:id="@+id/tv_origin_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:maxLines="1"
android:textColor="#999999"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@id/tv_current_price"
app:layout_constraintLeft_toRightOf="@id/tv_current_price"
tools:text="¥ 1480" />
</android.support.constraint.ConstraintLayout>
複製代碼
實現截圖:
要求:圖片寬度佔整個佈局30%,寬高比16:9。
分析:看到30%,首先考慮的是百分比佈局,可是圖片右邊的view較多,每一個都是設置一邊百分比,實在是麻煩。所以,能夠考慮使用Guideline,設置Guideline垂直,並距離父容器左邊30%的距離,以後佈局經過Guideline設置約束便可。
佈局XML:
<?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="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="12dp">
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.3"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/iv_course"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="fitXY"
android:src="@mipmap/test"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
...
</android.support.constraint.ConstraintLayout>
複製代碼
要求:在以前基礎上,底部加一根橫線用於分隔,要求線與上面最近的控件距離是15dp。
分析:因爲文字內容是可變的,當文字內容多的時候,線可能距離文字近;若文字很少,線也可能距離圖片近。這個時候,基於當前最新1.0.2穩定版本的約束佈局已經不能知足咱們實現一層佈局了,仍是須要將圖片和文字總體放入一個佈局容器中,而後橫線依賴這個佈局容器設置約束實現,嵌套好像在所不免了。然而,當約束佈局1.1.0穩定版本發佈時,這問題也能夠獲得解決。咱們先來看看在1.1.0上是怎麼實現的:
<?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="wrap_content"
android:paddingLeft="15dp"
android:paddingTop="12dp">
...
<android.support.constraint.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="iv_course, tv_origin_price"
/>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#d8d8d8"
android:layout_marginLeft="15dp"
android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@id/barrier"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
原來能夠經過Barrier實現,那麼Barrier是什麼?請往下看。
本文主要介紹ConstraintLayout的使用,所以也不大篇幅講述性能相關內容。
從Android studio 2.2版本開始,佈局編輯器支持拖拽的方式進行約束佈局。可是在2.2上佈局編輯器還不是很完善,部分約束不能設置,只能經過xml輸入方式實現。所以推薦用版本爲2.3或者更高的Android studio。
限於篇幅,這裏就不展開介紹佈局編輯器了。在這裏推薦兩篇文章,分別是ConstraintLayout 終極祕籍(下)和 Android新特性介紹,ConstraintLayout徹底解析。看完這兩篇,你們應該對佈局編輯器就會有比較深刻的瞭解了。
在使用約束佈局的過程當中,有一些須要強調的點和碰到的一些坑分享給你們。
咱們以前實現重疊佈局時,會經過設置負的margin值實現。可是在約束佈局中,負的margin值不會生效,只能設置0或者大於0的值,小於0也看成0處理。
通常佈局咱們都是遵照先定義,後使用原則,可是約束佈局實現鏈時,這個原則就遵照不了了。這個時候若是仍是按照常規的@id/btn_2
的方式指定依賴控件(這個控件在當前控件以後聲明的),就會報Error:(23, 46) No resource found that matches the given name錯誤。解決方案其實很簡單,只須要修改指定方式以下:@+id/btn_2
便可。
在代碼中設置控件約束,能夠經過ConstraintSet實現。約束變了以後,佈局確定會跟着變。TransitionManager.beginDelayedTransition
提供了平滑動畫變換佈局的能力,可是隻支持Api 19及以上的版本。
對Guideline設置相對位置屬性是不生效的,所以當咱們想要一個相對於某個view的Guideline時,約束佈局是不能知足咱們的要求的。 看Guideline源碼:
public class Guideline extends View {
public Guideline(Context context) {
super(context);
super.setVisibility(8);
}
...
}
複製代碼
發現Guideline是一個不可見的view,那麼咱們能夠佈局時放置一個不可見的view來做爲Guideline的替代品,實現一些特殊佈局要求。如佈局重疊:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_bias"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="zr.com.constraintdemo.normal.BiasActivity">
<Button
android:id="@+id/btn_a"
android:text="A"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent"
/>
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="1px"
app:layout_constraintBottom_toBottomOf="@id/btn_a"
android:layout_marginBottom="40dp"
/>
<Button
android:text="B"
android:background="@color/colorPrimary"
android:layout_width="wrap_content"
android:layout_height="200dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/view"
/>
</android.support.constraint.ConstraintLayout>
複製代碼
這種方式能夠彌補margin不能設置爲負值的不足,並且並無增長佈局層級。
match_parent
和MATCH_CONSTRAINT
app:layout_constraintWidth_min
等約束。layout_optimizationLevel
layout_editor_absoluteX
layout_editor_absoluteY
layout_constraintBaseline_creator
layout_constraintTop_creator
layout_constraintRight_creator
layout_constraintLeft_creator
layout_constraintBottom_creator
複製代碼
這幾個屬性是 UI 編輯器所使用的,用了輔助拖拽佈局的,在實際使用過程當中,能夠不用關心這些屬性。
最新的約束佈局beta版本,已經出到了1.1.0-beta3。在未來約束佈局1.1.0版本發佈後,其中會包含一下一些有意思的特性,讓人看了充滿期待。咱們先來一睹爲快:
Barrier
Barrier是一個虛擬的輔助控件,它能夠阻止一個或者多個控件越過本身,就像一個屏障同樣。當某個控件要越過本身的時候,Barrier會自動移動,避免本身被覆蓋。
Group
Group幫助你對一組控件進行設置。最多見的狀況是控制一組控件的visibility。你只需把控件的id添加到Group,就能同時對裏面的全部控件進行操做。
Circular positioning
能夠相對另外一個控件,以角度和距離定義當前控件的位置,即提供了在圓上定義控件位置的能力。如圖所示:
Placeholder
Placeholder顧名思義,就是用來一個佔位的東西,它能夠把本身的內容設置爲ConstraintLayout內的其它view。所以它用來寫佈局的模版,也能夠用來動態修改UI的內容。
百分比佈局
容許設置控件佔據可用空間的百分比,大大增長佈局靈活度和適配性。
總而言之,約束佈局的能力正在變得愈來愈強大。
曾幾什麼時候,對於複雜佈局,不少時候不是一種佈局就能夠解決。這時須要考慮佈局嵌套,又或者須要在代碼中動態設置控件寬高比,無形中增長了開發的複雜性和佈局的嵌套層級,進而影響了頁面性能。隨着google推出了ContraintLayout,上述的問題大部分均可以獲得有效的解決。
總的來講,ConstraintLayout優點以下:
本人經過在項目中的實踐,真切體會到了ConstraintLayout應對複雜佈局和自適應頁面的強大能力,不但下降了佈局難度,並且提高了開發效率。開發過程當中基本沒怎麼踩深坑,所以也很推薦你們在項目中去使用ConstraintLayout佈局。
附上demo的連接github.com/yushiwo/Con…,固然更建議你們本身去寫一遍,能夠加深印象。