一、傳統(tǒng)界面布局
在安卓開(kāi)發(fā)中,界面編程是一個(gè)很重要的部分,而很多時(shí)候?yàn)榱藢?shí)現(xiàn)好看的 ui 界面會(huì)用到很多層的布局來(lái)實(shí)現(xiàn),當(dāng)一個(gè)應(yīng)用的界面含有多個(gè)控件并且布局嵌套的層級(jí)大于三層時(shí)可能界面的渲染速度就會(huì)變慢,導(dǎo)致界面丟幀,這時(shí)界面加載起來(lái)就會(huì)很不流暢。極端情況下也會(huì)發(fā)生 ANR (Application Not Responding) 。因此一個(gè)優(yōu)秀的界面應(yīng)該盡量的去滿足以下兩點(diǎn)。
- 布局嵌套的層級(jí)經(jīng)可能的少
- 布局中的控件應(yīng)該盡可能的使用相對(duì)位置。
使用相對(duì)位置可以在不用分辨率的設(shè)備中保持布局效果的一致性。
但是以上兩點(diǎn)往往是沖突的,降低嵌套層級(jí)的方式是使用 RelativeLayout
, 而基于相對(duì)位置使用的是 LinearLayout
。當(dāng)界面過(guò)于復(fù)雜時(shí)需要大量的 LinearLayout
保證控件的相對(duì)擺放,這樣會(huì)導(dǎo)致嵌套層級(jí)過(guò)多,如果使用 RelativeLayout
控件之間的關(guān)系及其冗余,這時(shí)的界面可讀性差也難與修改。
二、ConstraintLayout布局
ConstraintLayout
即約束布局,在2016年的 Google I/O 大會(huì)上推出,可一定程度的替代掉 RelativeLayout
和 LinearLayout
接下來(lái)就開(kāi)始了解一些簡(jiǎn)單的用法。
- 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>
這個(gè)熟悉的代碼正是新版本的 Android Studio 新建項(xiàng)目時(shí)自動(dòng)生成的布局文件,可以看到這個(gè)界面的根布局正是 ConstraintLayout
。這個(gè)效果是讓 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>
- 圓形定位
這個(gè)用法簡(jiǎn)直是完美的解決了消息列表里使用圓形頭像時(shí)右上角的未讀消息的點(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 開(kāi)發(fā)強(qiáng)化實(shí)踐》
- Android新特性介紹,ConstraintLayout完全解析
- ConstraintLayout 官方文檔
- 約束布局ConstraintLayout看這一篇就夠了