如何寫出更高效的Android Layout

寫出高效 Layout 佈局文件的小技巧

在 Android 開發中,我們習慣關注的是怎麼寫出易用可讀以及高效能的 Java 程式碼,但是我們忽略了 layout 佈局文件。 Layout 佈局的 Render 速度會影響你的 App 執行速度。這邊介紹幾個小技巧來幫助我們寫出更多高效的 Layout 佈局文件

在一個 TextView 中使用複合的 drawable

我們常常會需要在 TextView 旁邊增加一張圖片,使用 TextView 本身的屬性同時顯示圖片和文字。

有些人首先想到的做法用一個 LinearLayout 或 RelativeLayout 來包含一個 TextView 和 ImageView,最後用到了三個UI元件和一堆 Layout 佈局程式碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/andropic1"/>
<TextView
android:layout_width="100dp"
android:layout_height="40dp"
android:text="layout tips"
android:textSize="18dp"
android:textAlignment="center"
android:gravity="center"/>
</LinearLayout>
</RelativeLayout>

example

用 TextView 的 compound drawable 是一個更好的解決方案。只要需一個屬性就能完成。修改後的佈局文件如下 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="120dp"
android:layout_height="40dp"
android:text="layout tips"
android:textSize="18dp"
android:textAlignment="center"
android:layout_centerInParent="true"
android:gravity="center"

android:drawableLeft="@drawable/andropic1"
android:drawableStart="@drawable/andropic1"
android:drawablePadding="0dp"
/>
</RelativeLayout>

ex

從上面佈局可以發現,變成只有一個 TextVIew 。但是如果要更改 drawable 的圖片size ,這種方式是沒有辦法在 layout 檔做修改的。

幾個主要屬性 :

  • drawableLeft - 指定 drawable 放在文字的左邊
  • drawableStart - 作用和 drawableLeft 相同,但是它是基於新的 Android 4.2 Api。支援RTL
  • drawablePadding - 指定文字和 drawable 之間 padding 多少

使用 LinearLayout 分隔線

分隔現在 app 非常常見。 LinearLayout 中有一個屬性可以幫你添加分隔線。

首先我們必須先創建一個 divider shape 來當作分隔線。

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="1dp"/>
<solid android:color="@color/colorPrimaryDark"/>
</shape>

接著將 shape 加入到 LinearLayout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@android:color/white"
android:divider="@drawable/divider_horizontal"
android:dividerPadding="5dp"
android:showDividers="middle">

<TextView
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Left"
android:textSize="20dp"/>

<TextView
android:layout_width="0dp"
android:layout_weight="0.5"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Right"
android:textSize="20dp"/>

</LinearLayout>
</RelativeLayout>

Imgur

主要有三個 xml 屬性

  • divider - 用來定義一個 drawable 或者 color 作為分隔線。
  • showDividers - 指定分隔線在哪裡顯示,可以顯示在開始位置、中間、結尾或者不顯示。
  • dividerPadding - 讓 divider 增加 padding 。

使用 Space 元件

當需要在兩個 UI 元件中添加間距的時時候,你可能會需要 padding or margin。有時候最後的 layout 文件可讀性很差。當你需要修改佈局元件時,你發現這裡有一個10dp 的 paddingTop,另外一邊又有一個 3dp 的 marginBottom,還有一個 8dp 的 paddingBottom在第三個元件上,這時候會很難去修改這樣的佈局元件。有些人會在兩個元件中增加 View 或 LinearLayout 來解決這個問題,看起來很簡單可以解決,但是或多或少會影響 app 的渲染效能,當這類的 View 元件更多時,更可能造成 App 執行緩慢。

這裡有一個更容易的方法就是 Space,Space 繼承 View,但是卻沒有在 canvas 中渲染任何事物。下面為 Space 元件的實現程式碼

1
2
3
4
5
6
7
8
/**
* Draw nothing.
*
* @param canvas an unused parameter.
*/
@Override
public void draw(Canvas canvas) {
}

使用方法非常簡單,只要在兩個元件中添加一個 Space 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="我是標題"
android:textSize="36dp"/>

<Space android:layout_width="match_parent"
android:layout_height="100dp"/>

<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="我是內容"/>

</LinearLayout>

Imgur

使用 標籤

重用佈局元件是一個保持 app 一致的方法,當以後有任何改變時,只需要更改一個元件就可以了。Android 提供了 標籤幫助你可以復用 Layout。

假設我們希望每個頁面都能有一個共用的 ToolBar。首先我們先創建一個共用的toolbar layout :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/Theme.AppCompat.Light.DarkActionBar"
android:fitsSystemWindows="true">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="ToolBar"
android:textColor="@color/colorAccent"
android:textSize="20dp"
android:gravity = "center"
android:id="@+id/toolbar_title" />

</android.support.v7.widget.Toolbar>

接著在我們原本的 layout 檔中 include 這個 toolbar layout :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<include
android:id="@+id/toolbar"
layout="@layout/toolbar"/>

</LinearLayout>

使用 標籤可以只用一行程式碼在app的每個頁面添加你的toolbar,任何改變都會自動更新到所有頁面。

Imgur

除了也常用來從你的 view 層次結構中減少不必要的元件,它會移除沒必要的嵌套的佈局,例如,如果被包含佈局文件的根是一個的LinearLayout ,然後你把它包括包含在另外一個的LinearLayout裡面,2個嵌套的LinearLayouts是沒有必要的,這個嵌套的佈局沒有任何作用除了影響UI性能。在這種情況下可以用來替換被包含佈局的根LinarLayout移除不必要的視圖。

關於的更多資訊你可以查看官方文檔