1. 程式人生 > >Android 佈局優化 include+merge+ViewStub標籤詳解

Android 佈局優化 include+merge+ViewStub標籤詳解

include 、merge、ViewStub標籤詳解

一.include標籤

include標籤常用於將佈局中的公共部分提取出來供其他layout使用,以實現佈局模組化。

程式碼

1.1.公共Layout

<?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="80dp"
    android:background="@color/app_color"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_marginTop="20dp"
        android:layout_height="60dp">

        <RelativeLayout
            android:id="@+id/apptoplayout_onlyback_backlayout"
            android:layout_width="60dp"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true">

            <ImageView
                android:id="@+id/apptoplayout_onlyback_imageview"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:scaleType="fitCenter"
                android:background="@mipmap/back" />
        </RelativeLayout>

        <TextView
            android:id="@+id/apptoplayout_onlyback_titletextview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginTop="20dp"
            android:layout_alignParentRight="true"
            android:layout_marginRight="60dp"
            android:layout_toRightOf="@+id/apptoplayout_onlyback_backlayout"
            android:gravity="center"
            android:singleLine="true"
            android:ellipsize="end"
            android:textColor="@color/whilecolor"
            android:textSize="16sp" />

    </RelativeLayout>

</LinearLayout>

1.2.引入使用頁面的Layout

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

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


    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/appbackground_color"
        android:scrollbars="none">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            ......

        </LinearLayout>

    </ScrollView>

</LinearLayout>

即:

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

1.3.引入使用的Activity

titletextview= (TextView) findViewById(R.id.apptoplayout_onlyback_titletextview);

這樣就可以了。

注意:被引入的模組佈局父佈局要確定寬高(尤其是高)然後直接引入即可。如果不確定寬高都是(match_parent)就要在引入的時候確定寬高

多個佈局

layout1

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

    <Button
        android:id="@+id/includelayout1_button"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_marginTop="10dp"
        android:background="@color/btn_answer_normal"
        android:text="佈局一按鈕"
        android:textColor="#FFFFFF" />

</LinearLayout>

layout2

<?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="100dp"
    android:orientation="vertical">

    <Button
        android:id="@+id/includelayout2_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/btn_gray_pressed"
        android:text="佈局二按鈕"
        android:layout_marginTop="10dp"
        android:textColor="#FFFFFF" />

</LinearLayout>

layout3

<?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="100dp"
    android:orientation="vertical">

    <Button
        android:id="@+id/includelayout3_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/btn_logout_normal"
        android:text="佈局三按鈕"
        android:layout_marginTop="10dp"
        android:textColor="#FFFFFF" />

</LinearLayout>

主頁面佈局

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

    <include
        layout="@layout/includelayout1"
        android:layout_width="match_parent"
        android:layout_height="100dp" />

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

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

</LinearLayout>

主頁面效果

主頁面使用

package wjn.com.imwithdemo.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import wjn.com.imwithdemo.R;

public class IncludeDemoActivity extends AppCompatActivity {

    private Button button1;
    private Button button2;
    private Button button3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_includedemo);

        button1=findViewById(R.id.includelayout1_button);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(IncludeDemoActivity.this,"按鈕一被點選!",Toast.LENGTH_LONG).show();
            }
        });

        button2=findViewById(R.id.includelayout2_button);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(IncludeDemoActivity.this,"按鈕二被點選!",Toast.LENGTH_LONG).show();
            }
        });

        button3=findViewById(R.id.includelayout3_button);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(IncludeDemoActivity.this,"按鈕三被點選!",Toast.LENGTH_LONG).show();
            }
        });

    }
}

附:include官方文件

二.merge標籤

merge用於消除檢視層次結構中的冗餘檢視,例如根佈局是Linearlayout,那麼我們又include一個LinerLayout佈局就沒意義了,反而會減慢UI載入速度。

又或者根佈局是FrameLayout且不需要設定background或padding等屬性,可以用merge代替,因為Activity的ContentView父元素就是FrameLayout,所以可以用merge消除只剩一個。

程式碼

被引入的佈局

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

    <Button
        android:id="@+id/includelayout1_button1"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_marginTop="10dp"
        android:background="@color/btn_answer_normal"
        android:text="佈局一按鈕一"
        android:textColor="#FFFFFF" />

    <Button
        android:id="@+id/includelayout1_button2"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_marginTop="10dp"
        android:background="@color/btn_green_pressed"
        android:text="佈局一按鈕二"/>

</merge>

主頁面layout

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

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

</LinearLayout>

主頁面效果

主頁面程式碼

package wjn.com.imwithdemo.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import wjn.com.imwithdemo.R;

public class IncludeDemoActivity extends AppCompatActivity {

    private Button button1;
    private Button button2;
    private Button button3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_includedemo);

        button1=findViewById(R.id.includelayout1_button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(IncludeDemoActivity.this,"按鈕一被點選!",Toast.LENGTH_LONG).show();
            }
        });

        button2=findViewById(R.id.includelayout1_button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(IncludeDemoActivity.this,"按鈕二被點選!",Toast.LENGTH_LONG).show();
            }
        });


    }
}

 主頁面父佈局是LinearLayout且垂直排布,要引入的佈局父佈局也是LinearLayout且垂直排布。這樣的話被引入的佈局父佈局完全可以修改成merge。這樣系統忽略<merge />節點並且直接新增兩個Button。

附:merge官方文件

三.ViewStub標籤

ViewStub 標籤最大的優點是當你需要時才會載入,使用他並不會影響UI初始化時的效能。各種不常用的佈局比如進度條、顯示錯誤訊息等可以使用<ViewStub />標籤,以減少記憶體使用量,加快渲染速度。

程式碼

textview佈局

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

    <TextView
        android:id="@+id/textview_layout_textview"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/btn_gray_pressed_status"
        android:textColor="#FFFFFF"
        android:gravity="center"
        android:text="我是TextView"/>

</LinearLayout>

imageview佈局

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

    <ImageView
        android:id="@+id/imageview_layout_imageview"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:background="@mipmap/ic_launcher"
        android:scaleType="fitXY" />

</LinearLayout>

主頁面layout

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

    <Button
        android:id="@+id/activity_viewstubdemo_button"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/btn_login_pressed"
        android:text="顯示文字"/>

    <ViewStub
        android:id="@+id/activity_viewstubdemo_viewstub1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout="@layout/textview_layout"/>

    <ViewStub
        android:id="@+id/activity_viewstubdemo_viewstub2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout="@layout/imageview_layout"/>

</LinearLayout>

主頁面效果

主頁面程式碼

package wjn.com.imwithdemo.activity;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewStub;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import wjn.com.imwithdemo.R;

public class ViewStubDemoActivity extends AppCompatActivity {

    private Button button;
    private boolean showTextViewOrImageView=false;
    private ViewStub viewstub1;
    private View view1;
    private TextView textview;
    private ViewStub viewstub2;
    private View view2;
    private ImageView imageview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_viewstubdemo);

        button=findViewById(R.id.activity_viewstubdemo_button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!showTextViewOrImageView){
                    viewstub1=findViewById(R.id.activity_viewstubdemo_viewstub1);
                    if(null==view1){
                        view1=viewstub1.inflate();
                    }
                    textview=findViewById(R.id.textview_layout_textview);
                    textview.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Toast.makeText(ViewStubDemoActivity.this,"文字點選!",Toast.LENGTH_LONG).show();
                        }
                    });
                    button.setText("顯示文字");
                    showTextViewOrImageView=true;
                }else{
                    viewstub2=findViewById(R.id.activity_viewstubdemo_viewstub2);
                    if(null==view2){
                        view2=viewstub2.inflate();
                    }
                    imageview=findViewById(R.id.imageview_layout_imageview);
                    imageview.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            Toast.makeText(ViewStubDemoActivity.this,"圖片點選!",Toast.LENGTH_LONG).show();
                        }
                    });
                    button.setText("顯示圖片");
                    showTextViewOrImageView=false;
                }
            }
        });
    }
}

注意:

1.由於ViewStub第一次inflate的時候,就已經將需要顯示的佈局替換掉自己了,所以第二次inflate的時候,getParent()是null,所以就會報異常。解決方法是inflate()的時候將view儲存起來,然後下次判斷這個View是否為NUll,如果是null就inflate().否則就直接使用這個view。

2.也可通過以下方式獲取

findViewById(R.id.activity_viewstubdemo_viewstub2).setVisibility(View.VISIBLE);