相信大家經常聽到`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`的使用就介紹到這裏了,具體使用情況還得視項目而定。