尊重原創,轉載請註明出處:http://blog.csdn.net/a740169405/article/details/50473909
Android 官方提供了三個用來優化佈局的標籤,分別是include、merge與ViewStub,其中ViewStub是動態加載視圖到內存,大家可以查閱:Android UI佈局優化之ViewStub
一、include佈局重用:
在Android的應用程序開發中,標題欄是必不可少的一個元素,大部分頁面都要用到,而且佈局都是一樣的,這時候使用include標籤就顯得極其的方便。使用時通常需要注意以下幾點。
- include標籤的layout_*屬性會替換掉被include視圖的根節點的對應屬性。
- include標籤的id屬性會替換掉被include視圖的根節點id
- 一個佈局文件中支持include多個視圖,但是這樣會導致獲取被include視圖內的控件時, 解決方法請參考:www.coboltforge.com/2012/05/tech-stuff-layout/
下面例子中,titlebar_layout.xml爲標題欄佈局,而activity_main.xml爲主界面佈局,activity_setting.xml爲設置頁面佈局,這這兩個界面中都include了titlebar_layout.xml視圖。 titlebar_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/preference_activity_title_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dip"
android:background="@drawable/zns_activity_title_bg">
<TextView
android:id="@+id/preference_activity_title_text"
android:layout_width="match_parent"
android:layout_height="45dip"
android:gravity="center"
android:text="123"
android:textColor="#ffffff"
android:textSize="18sp" />
<ImageView
android:id="@+id/preference_activity_title_image"
android:layout_width="30dip"
android:layout_height="25dip"
android:layout_gravity="center_vertical"
android:scaleType="fitCenter"
android:layout_marginLeft="5dip"
android:src="@drawable/common_menu_selector_white" />
</FrameLayout>
- 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
- 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
主界面:
<?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"
android:background="#000000">
<include layout="@layout/titlebar_layout"></include>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="這是內容區域"
android:gravity="center"
android:textSize="25sp"
android:textColor="#ffffff"/>
</LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
當然,其他界面使用include同樣能包含該標題欄。
一、通過merge減少視圖節點:
merge翻譯成中文是合併的意思,在Android中通過使用merge能夠減少視圖的節點數,
從而減少視圖在繪製過程消耗的時間,達到提高UI性能的效果。使用merge時通常需要注意以下幾點:
- merge必須放在佈局文件的根節點上。
- merge並不是一個ViewGroup,也不是一個View,它相當於聲明瞭一些視圖,等待被添加。
- merge標籤被添加到A容器下,那麼merge下的所有視圖將被添加到A容器下。
- 因爲merge標籤並不是View,所以在通過LayoutInflate.inflate方法渲染的時候, 第二個參數必須指定一個父容器,且第三個參數必須爲true,也就是必須爲merge下的視圖指定一個父親節點。
- 如果Activity的佈局文件根節點是FrameLayout,可以替換爲merge標籤,這樣,執行setContentView之後,會減少一層FrameLayout節點。
- 自定義View如果繼承LinearLayout,建議讓自定義View的佈局文件根節點設置成merge,這樣能少一層結點。
- 因爲merge不是View,所以對merge標籤設置的所有屬性都是無效的。
其中第一點,我們看看LayoutInflate類的源碼說明:
} else if (TAG_MERGE.equals(name)) {
// 如果merge不是根節點,報錯
throw new InflateException("<merge /> must be the root element");
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
其中第三點,常用在自定義View中遇到,附上系統LayoutInflate類,對於該現象的源碼:
if (TAG_MERGE.equals(name)) {
// 如果是merge標籤,指定的root爲空,或則attachToRoot爲false,則拋出異常信息
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, attrs, false, false);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
針對第五點,做一下對比:
佈局文件1:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="頂部Button" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="底部Button" />
</merge>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
效果1:
佈局文件2:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:text="頂部Button" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="底部Button" />
</FrameLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
效果2:
我們可以看到,如果使用merge,明顯少了一個FrameLayout節點,這也算一個視圖優化技巧。
下面對第六條(自定義View如果繼承LinearLayout,建議讓自定義View的佈局文件根節點設置成merge,這樣能少一層結點)進行分析:
先看看效果,就是一個線性佈局,上下各一個TextView,看看使用merge和不使用merge的視圖節點,
以及使用merge的時候layoutInflate類的注意點。
效果圖:
第一種情況(不使用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:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:background="#000000"
android:gravity="center"
android:text="第一個TextView"
android:textColor="#ffffff" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:background="#ffffff"
android:gravity="center"
android:text="第一個TextView"
android:textColor="#000000" />
</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
- 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
代碼:
/**
* 自定義的View,豎直方向的LinearLayout
*/
public class MergeLayout extends LinearLayout {
public MergeLayout(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.merge_activity, this, true);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
視圖樹:
我們發現,MergeLayout這個自定義控件的下面並不是直接跟着兩個TextView,
而是多了一個LinearLayout。
第二種情況(使用merge):
注意因爲爲merge標籤的設置的屬性都不會生效,所以原來LinearLayout標籤上的屬性需要轉移到Java代碼中設置。
佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<!-- 習慣性的標記一下,MergeLayout佈局 android:orientation="vertical" -->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:background="#000000"
android:gravity="center"
android:text="第一個TextView"
android:textColor="#ffffff" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:background="#ffffff"
android:gravity="center"
android:text="第一個TextView"
android:textColor="#000000" />
</merge>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
個人習慣在用merge的時候在旁邊標明使用到的屬性,以防忘記。
java代碼中需要設置orientation屬性:
/**
* 自定義的View,豎直方向的LinearLayout
*/
public class MergeLayout extends LinearLayout {
public MergeLayout(Context context) {
super(context);
// 設置爲數值方向的佈局
setOrientation(VERTICAL);
LayoutInflater.from(context).inflate(R.layout.merge_activity, this, true);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
再看看視圖樹:
我們發現,LinearLayout節點被去掉了。但是最終顯示給用戶的界面卻是一樣的。
總結
1. 使用include標籤可以增加布局的複用性,提高效率。
2. 使用merge標籤可以減少視圖樹中的節點個數,加快視圖的繪製,提高UI性能。
3. merge標籤的使用,看上去一次只減少一個節點,但是當一個佈局嵌套很複雜的時候,
節點的個數可能達到幾百個,這個時候,如果每個地方都多一個節點,視圖的繪製時間相應的也就變長了很多。