Android 佈局優化的幾個技巧

1、重用< include/>

< include>標籤可以在一個佈局中引入另外一個佈局,做到佈局的重用

如下代碼是項目中的一個公共的標題欄佈局title_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="?android:actionBarSize"
    android:background="@color/common_title_background">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:src="@drawable/ic_menu_back" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="@color/white"
        android:textSize="@dimen/common_text_size_36"
        tools:text="@string/app_task_title" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:gravity="center"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:textColor="@color/white"
        android:textSize="@dimen/common_text_size_32"
        tools:text="@string/filter_title" />
</RelativeLayout>

Preview:


接下來就可以在其他佈局中重用這個佈局了,代碼如下:

<?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">

    <include
        layout="@layout/title_bar"/>

</Relativelayout>

2、合併

減少嵌套

  • 在不影響層級深度的情況下,使用LinearLayout而不是RelativeLayout。因爲RelativeLayout會讓子View調用2次onMeasure,LinearLayout 在有weight時,纔會讓子View調用2次onMeasure。Measure的耗時越長那麼繪製效率就低。

  • 如果非要是嵌套,那麼儘量避免RelativeLayout嵌套RelativeLayout。這將是惡性循環。

<merge/>

  • 子視圖不需要指定任何針對父視圖的佈局屬性。

  • 假如需要在LinearLayout裏面嵌入一個佈局,而這個佈局的根節點也是LinearLayout,這樣就多了一層沒有用的嵌套,無疑這樣只會拖慢程序速度。而這個時候如果我們使用merge根標籤就可以避免那樣的問題

例如我們可以將之前的佈局替換成下面的:

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include
        layout="@layout/title_bar"/>

</merge>

我們可以通過Android Studio的View Hierarchy工具來查看比較這兩個佈局文件的區別。

3、按需載入ViewStub

每天的開發過程中經常遇到這樣的情況,根據不同的條件來決定哪些View顯示以及隱藏,通常我們的做法是將其加入到佈局中設置其不可見,用的時候在設置可見,這樣的話是會創建view的,並無形中影響了性能。
其實我們可以用ViewStub來替換,他是一個輕量級的View,不佔佈局的位置,而且佔用的資源很小。
例如,我們有個重複的開關,默認進入是關閉的,打開後可以選擇開始時間和結束時間,佈局文件如下:

<?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">

    <Switch
        android:id="@+id/switch_repeat"
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:padding="@dimen/left_margin"
        android:text="@string/repeat"
        android:textSize="@dimen/common_text_size_36" />

    <ViewStub
        android:id="@+id/view_datetime_picker"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:inflatedId="@+id/view_datetime_picker"
        android:layout="@layout/view_datetime_picker" />

</LinearLayout>
在activity或者fragment中的用法:
mSwitchButton.setOnCheckedChangeListener(
                new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView,
                            boolean isChecked) {
                        if (isChecked) {
                            if (datePickView == null) {
                                ViewStub viewStub = (ViewStub) ContactRemindSettingActivity.this
                                        .findViewById(
                                                R.id.view_datetime_picker);
                                datePickView = viewStub.inflate();
                            }
                            datePickView.setVisibility(View.VISIBLE);
                        } else {
                            if (datePickView != null) {
                                datePickView.setVisibility(View.GONE);
                            }
                        }
                    }
                });

4、巧用LinearLayout自帶分割線

一般我們的設置頁面都會有很多條目,每個條目之間都是有一根分割線的,一般很多的人做法是用一個view來佔據空間,其實我們可以用LinearLayout的分割線,代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="@drawable/divider"
    android:orientation="vertical"
    android:showDividers="beginning|end|middle">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/white"
        android:drawableLeft="@drawable/ic_personal_invitation"
        android:drawablePadding="@dimen/left_margin"
        android:drawableRight="@drawable/icon_message_more"
        android:gravity="center_vertical"
        android:padding="@dimen/left_margin"
        android:text="未完成事項"
        android:textSize="@dimen/common_text_size_36" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/white"
        android:drawableLeft="@drawable/ic_personal_notice"
        android:drawablePadding="@dimen/left_margin"
        android:drawableRight="@drawable/icon_message_more"
        android:gravity="center_vertical"
        android:padding="@dimen/left_margin"
        android:text="未完成事項"
        android:textSize="@dimen/common_text_size_36" />


    <TextView
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/white"
        android:drawableLeft="@drawable/ic_personal_opinion"
        android:drawablePadding="@dimen/left_margin"
        android:drawableRight="@drawable/icon_message_more"
        android:gravity="center_vertical"
        android:padding="@dimen/left_margin"
        android:text="檢查更新"
        android:textSize="@dimen/common_text_size_36" />

</LinearLayout>

效果圖:


其中divider.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <size
        android:width="1dp"
        android:height="1dp" />

    <solid android:color="@color/divider_color" />

</shape>

showDividers是設置分割線的位置,有三個選項,diverPadding是給divider設置padding的

5、Space控件

上面的頁面如果需要將檢查更新和其他的進行分離,另成一組怎麼辦,這時Space就起作用了,相信很多人會用view或者設置topMatgin來實現。
Space源碼如下,其實它在draw中未繪製任何東西,所以性能是幾乎沒有影響的,大可放心使用。
/**
 * Space is a lightweight View subclass that may be used to create gaps between components
 * in general purpose layouts.
 */
public final class Space extends View {
    /**
     * {@inheritDoc}
     */
    public Space(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        if (getVisibility() == VISIBLE) {
            setVisibility(INVISIBLE);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Space(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    /**
     * {@inheritDoc}
     */
    public Space(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * {@inheritDoc}
     */
    public Space(Context context) {
        //noinspection NullableProblems
        this(context, null);
    }

    /**
     * Draw nothing.
     *
     * @param canvas an unused parameter.
     */
    @Override
    public void draw(Canvas canvas) {
    }

    /**
     * Compare to: {@link View#getDefaultSize(int, int)}
     * If mode is AT_MOST, return the child size instead of the parent size
     * (unless it is too big).
     */
    private static int getDefaultSize2(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                result = size;
                break;
            case MeasureSpec.AT_MOST:
                result = Math.min(size, specSize);
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
        }
        return result;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(
                getDefaultSize2(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize2(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
}

佈局文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/lightgray"
    android:divider="@drawable/divider"
    android:orientation="vertical"
    android:showDividers="beginning|end|middle">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/white"
        android:drawableLeft="@drawable/ic_personal_invitation"
        android:drawablePadding="@dimen/left_margin"
        android:drawableRight="@drawable/icon_message_more"
        android:gravity="center_vertical"
        android:padding="@dimen/left_margin"
        android:text="未完成事項"
        android:textSize="@dimen/common_text_size_36" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/white"
        android:drawableLeft="@drawable/ic_personal_notice"
        android:drawablePadding="@dimen/left_margin"
        android:drawableRight="@drawable/icon_message_more"
        android:gravity="center_vertical"
        android:padding="@dimen/left_margin"
        android:text="未完成事項"
        android:textSize="@dimen/common_text_size_36" />


    <Space
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:background="@color/black" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:background="@color/white"
        android:drawableLeft="@drawable/ic_personal_opinion"
        android:drawablePadding="@dimen/left_margin"
        android:drawableRight="@drawable/icon_message_more"
        android:gravity="center_vertical"
        android:padding="@dimen/left_margin"
        android:text="檢查更新"
        android:textSize="@dimen/common_text_size_36" />

</LinearLayout>

效果:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章