一、傳統(tǒng)界面布局
在安卓開發(fā)中,界面編程是一個很重要的部分,而很多時候?yàn)榱藢?shí)現(xiàn)好看的 ui 界面會用到很多層的布局來實(shí)現(xiàn),當(dāng)一個應(yīng)用的界面含有多個控件并且布局嵌套的層級大于三層時可能界面的渲染速度就會變慢,導(dǎo)致界面丟幀,這時界面加載起來就會很不流暢。極端情況下也會發(fā)生 ANR (Application Not Responding) 。因此一個優(yōu)秀的界面應(yīng)該盡量的去滿足以下兩點(diǎn)。
- 布局嵌套的層級經(jīng)可能的少
- 布局中的控件應(yīng)該盡可能的使用相對位置。
使用相對位置可以在不用分辨率的設(shè)備中保持布局效果的一致性。
但是以上兩點(diǎn)往往是沖突的,降低嵌套層級的方式是使用 RelativeLayout, 而基于相對位置使用的是 LinearLayout。當(dāng)界面過于復(fù)雜時需要大量的 LinearLayout 保證控件的相對擺放,這樣會導(dǎo)致嵌套層級過多,如果使用 RelativeLayout控件之間的關(guān)系及其冗余,這時的界面可讀性差也難與修改。
二、ConstraintLayout布局
ConstraintLayout 即約束布局,在2016年的 Google I/O 大會上推出,可一定程度的替代掉 RelativeLayout 和 LinearLayout 接下來就開始了解一些簡單的用法。
- Hello World 的布局
<?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=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
這個熟悉的代碼正是新版本的 Android Studio 新建項(xiàng)目時自動生成的布局文件,可以看到這個界面的根布局正是 ConstraintLayout。這個效果是讓 Hello World! 居中,其標(biāo)準(zhǔn)性模板如下
app:layout_constraint[ 本源位置 ]_to[ 目標(biāo)位置 ]="[ 目標(biāo)id ]"
- 指定約束
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/cancel_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:text="取消"
app:layout_constraintBottom_toBottomOf="@id/constraintLayout"
app:layout_constraintStart_toStartOf="@id/constraintLayout" />
<Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:text="下一步"
app:layout_constraintBottom_toBottomOf="@id/constraintLayout"
app:layout_constraintStart_toEndOf="@id/cancel_button" />
</android.support.constraint.ConstraintLayout>

- 設(shè)置比例
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="居中"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintEnd_toEndOf="@id/constraintLayout"
app:layout_constraintStart_toStartOf="@id/constraintLayout"
app:layout_constraintTop_toTopOf="@+id/constraintLayout" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按比例偏移"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintEnd_toEndOf="@id/constraintLayout"
app:layout_constraintHorizontal_bias="0.25"
app:layout_constraintStart_toStartOf="@id/constraintLayout"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintVertical_bias="0.25" />
</android.support.constraint.ConstraintLayout>

- 引導(dǎo)線布局
<?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/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.Guideline
android:id="@+id/guideLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="72dp"
tools:layout_editor_absoluteX="72dp"
tools:layout_editor_absoluteY="0dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="向上"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintStart_toStartOf="@id/guideLine"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintVertical_bias="0.25"
tools:layout_editor_absoluteX="72dp" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="向下"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintStart_toStartOf="@id/guideLine"
app:layout_constraintTop_toTopOf="@+id/constraintLayout"
app:layout_constraintVertical_bias="0.75"
tools:layout_editor_absoluteX="72dp" />
</android.support.constraint.ConstraintLayout>

- 布局填充
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/small"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:text="自適應(yīng)大小"
app:layout_constraintStart_toStartOf="@id/constraintLayout"
app:layout_constraintTop_toTopOf="@id/constraintLayout" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="取最寬的寬度"
app:layout_constraintBottom_toBottomOf="@id/constraintLayout"
app:layout_constraintEnd_toEndOf="@id/constraintLayout"
app:layout_constraintStart_toEndOf="@id/small"
app:layout_constraintTop_toTopOf="@id/constraintLayout" />
</android.support.constraint.ConstraintLayout>

- 控件寬高比
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="0dp"
android:layout_height="200dp"
android:background="@color/colorAccent"
android:src="@mipmap/home_ban"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="@+id/constraintLayout"
app:layout_constraintRight_toRightOf="@+id/constraintLayout"
app:layout_constraintTop_toTopOf="@+id/constraintLayout" />
<ImageView
android:layout_width="200dp"
android:layout_height="0dp"
android:background="@color/colorAccent"
android:contentDescription="@null"
android:src="@mipmap/home_ban"
app:layout_constraintBottom_toBottomOf="@+id/constraintLayout"
app:layout_constraintDimensionRatio="4:3"
app:layout_constraintLeft_toLeftOf="@+id/constraintLayout"
app:layout_constraintRight_toRightOf="@+id/constraintLayout" />
</android.support.constraint.ConstraintLayout>

- 圓形定位
這個用法簡直是完美的解決了消息列表里使用圓形頭像時右上角的未讀消息的點(diǎn)。
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/pic"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@mipmap/login_sel_rel"
app:layout_constraintCircle="@+id/image"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="70dp" />
</android.support.constraint.ConstraintLayout>

參考資料
- 《Android 開發(fā)強(qiáng)化實(shí)踐》
- Android新特性介紹,ConstraintLayout完全解析
- ConstraintLayout 官方文檔
- 約束布局ConstraintLayout看這一篇就夠了