Android 佈局巧用之include、merge、ViewStub

相信大家經常聽到`include`、`merge`、`ViewStub`這樣的標籤,官方也提到這三種佈局可用於佈局的優化。今天就介紹下這三種佈局的使用,記錄下來,便於後續app中的使用。


include佈局重用


app開發過程中,會遇到不同頁面裏有相同的佈局,這時我們可以將這些通用的佈局提取出來到一個單獨的`layout`文件裏,再使用`<include>`標籤引入到相應的頁面佈局文件裏,主要通過`include`的`layout`屬性引用。  

舉個栗子  

`include`的佈局:


```

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/container"

    android:layout_width="match_parent"

    android:layout_height="wrap_content">


    <TextView

        android:id="@+id/tv1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="這裏是來自include佈局" />


</RelativeLayout>


```




`activity`的佈局:


```

<?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:id="@+id/tv2"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="以下的內容來自include標籤" />


    <include

        android:id="@+id/container"

        layout="@layout/include_layout"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@+id/tv"

        android:layout_marginTop="10dp" />


</RelativeLayout>


```



這個標籤在日常工作使用還是很常見的。這裏有幾點需要注意下:  

1、如果給`include`標籤 和 `include`所加載的佈局 都添加id的話,那麼id要保持一致,如例子中都是`container`,否則是在代碼中獲取不到`RelativeLayout`容器的。 當然我們可以避免這樣的問題,只需要給其中一項添加id屬性就可以。


2、`include`佈局裏元素的id 要和  `include`所在頁面佈局裏的其他元素id 不同,如例子中的兩個`textview`,如果把id設置相同了,程序運行起來並不會報錯,但是`textview`的賦值只會賦值給其中的一個。


3、如果需要給`include`標籤設置位置屬性的話,如例子中的`layout_below`、`layout_marginTop`,這時候 **必須** 同時設置`include`標籤的寬高屬性`layout_width`、`layout_height`,否則編譯器是會報錯的。一般情況不需要設置`include`的其他屬性,直接加載佈局文件 `<include layout="@layout/...."/>`


4、佈局中可以包含兩個相同的include標籤,如下代碼所示 兩個`include`都加載`layout="@layout/include_layout"`


```

<?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:id="@+id/tv"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="以下的內容來自include標籤" />


    <include

        android:id="@+id/container"

        layout="@layout/include_layout"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@+id/tv"

        android:layout_marginTop="10dp" />


    <include

        android:id="@+id/container2"

        layout="@layout/include_layout"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginTop="80dp" />


</RelativeLayout>


```



可以設置不同`include`的id屬性,引用的時候如下可以正常顯示:


```

View view = findViewById(R.id.container2);

TextView textView = view.findViewById(R.id.tv);

textView.setText("這裏是來自 第二個 include佈局");


```




### merge減少視圖層級


`merge`標籤可用於減少視圖層級來優化佈局,可以配合`include`使用,如果`include`標籤的父佈局 和 `include`佈局的根容器是相同類型的,那麼根容器的可以使用`merge`代替。  

頁面佈局


```

<?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:id="@+id/tv"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="以下的內容不是來自merge標籤" />


    <include

        layout="@layout/merge_layout"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginTop="20dp" />


</LinearLayout>


```



先看沒有使用`merge`的:


```

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content">


    <TextView

        android:id="@+id/tv"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="這裏是不是來自merge佈局" />


</LinearLayout>


```



看下view層的結構:  


![image.png](https://upload-images.jianshu.io/upload_images/13855150-cf4b35d956e67f61.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)




再看使用了`merge`的:


```

<?xml version="1.0" encoding="utf-8"?>

<merge xmlns:android="http://schemas.android.com/apk/res/android">


    <TextView

        android:id="@+id/tv"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="這裏是來自merge佈局" />


</merge>


```



view層結構:  


![image.png](https://upload-images.jianshu.io/upload_images/13855150-4cf1c7c7d6281c1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



可以看到對比,減少了一層的`LinearLayout`的嵌套,需要注意的是使用`merge`的佈局,在`include`的標籤設置距離屬性沒有生效,可以將一些間距屬性設置到`include`佈局裏元素上,具體看項目需求使用。


ViewStub按需加載


按需加載 顧名思義需要的時候再去加載,不需要的時候可以不用加載,節約內存使用。通常情況我們會使用`setVisibility`方法來控制視圖的顯示和隱藏,但是這種情況視圖已經加載了。   

比如app中頁面裏某個佈局只需要在特定的情況下才顯示,其餘情況下可以不用加載顯示,這時候可以使用`ViewStub`。  

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


    <ViewStub

        android:id="@+id/viewstub"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginTop="20dp"

        android:layout="@layout/viewstub_layout" />


</LinearLayout>


```




需要注意的是 `ViewStub`的`inflate()`方法只能被調用一次,一旦調用後,`ViewStub`將從視圖中移除,被對應的`layout`佈局取代,同時會保留`ViewStub`上設置的屬性效果。


```

ViewStub viewstub = findViewById(R.id.viewstub);

viewstub.inflate();


```




這篇關於`include`、`merge`、`ViewStub`的使用就介紹到這裏了,具體使用情況還得視項目而定。


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