在XML中定義Android的Layout時,有四個比較特別的標籤是非常重要的,分別是<viewStub/>, <requestFocus />, <merge /> 和<include />,其中有三個是與資源複用有關。
1)<ViewStub />標籤
ViewStub是一個不可見的,大小爲0的View,最佳用途就是實現View的延遲加載,在需要的時候再加載View,和Java中常見的性能優化方法延遲加載一樣。當調用ViewStub的setVisibility函數設置爲可見或則調用inflate()方法初始化該View的時候,ViewStub引用的資源開始初始化,然後引用的資源會替代掉ViewStub,把自己填充在ViewStub的原位置。因此在沒有調用setVisibility(int)或inflate()方法之前ViewStub會一直存在組件樹層級結構中,但是由於ViewStub非常輕量級,這對性能影響非常小。可以通過ViewStub的inflatedId屬性來重新定義引用的layout的id(也就是說,加入我們所引用的layout的id是R.layout.prelayout,然後我們在ViewStub中添加屬性android:inflatedId="@+id/subLayout“,那麼我們就可以用R.layout.subLayout來引用這個layout了)。
示例:
<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subLayout"
android:layout="@layout/preLayout"
android:layout_width="120dip"
android:layout_height="40dip" />
上面定義的ViewStub我們可以通過findViewById(R.id.stub)來找到,在初始化資源preLayout後,ViewStub從父組件中刪除,然後preLayout替代ViewStub的位置。初始資源preLayout得到的組件可以通過inflatedId 指定的id "subLayout"引用。 然後初始化後的資源被填充到一個120dip寬、40dip高的地方。
推薦使用下面的方式來初始化ViewStub:
ViewStub stub = (ViewStub) findViewById(R.id.stub);
View inflated = stub.inflate();
當調用inflate()函數的時候,ViewStub被引用的資源替代,並且返回引用的view。 這樣程序可以直接得到引用的view而不用再次調用函數findViewById()來查找了。
注:ViewStub目前有個缺陷就是還不支持 <merge /> 標籤。
2)<include />標籤
可以通過這個標籤直接加載外部的xml到當前結構中,是複用UI資源的常用標籤。
用法:將需要複用xml文件路徑賦予include標籤的Layout屬性。
<include android:id="@+id/cell1" layout="@layout/ar01" />
<include android:layout_width="fill_parent" layout="@layout/ar01" />
注:
1.include標籤只有layout屬性是必須的<include layout="@layout/layout_ID"/>
2.include標籤若指定了ID屬性,而你的layout也定義了ID,則你的layout的ID會被覆蓋
<include android:id="@+id/your_ID" layout="@layout/layout_ID"/>
3.在include標籤中所有的android:layout_*都是有效的。但前提是必須要寫layout_width和layout_height兩個屬性,否則無效 。
3)<requestFocus />標籤
標籤用於指定屏幕內的焦點View。
用法: 將標籤置於Views標籤內部
<EditText id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4">
<requestFocus />
</EditText>
4)<merge />標籤
它在優化UI結構時起到很重要的作用,目的是通過刪減多餘或者額外的層級,從而優化整個Android的Layout結構。
示例:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:scaleType="center"
android:src="http://ygc87.blog.163.com/blog/@drawable/icon" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom" android:padding="12dip"
android:background="#AA000000" android:textColor="#ffffffff"
android:text="Golden Gate" />
</FrameLayout>
運行上邊的layout,然後啓動 tools> hierarchyviewer.bat工具查看當前UI結構視圖:
我們可以很明顯的看到出現了兩個framelayout節點,這兩個意義完全相同的節點造成了資源浪費(這裏可以提醒大家在開發工程中可以習慣性的通過hierarchyViewer查看當前UI資源的分配情況),那麼如何才能解決這種問題呢(就當前例子是如何去掉多餘的frameLayout節點),這時候就要用到<merge />標籤來處理類似的問題了。我們將上邊xml代碼中的FrameLayout替換成merge:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ImageView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:scaleType="center"
android:src="http://ygc87.blog.163.com/blog/@drawable/icon" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_marginBottom="20dip"
android:layout_gravity="center_horizontal|bottom" android:padding="12dip"
android:background="#AA000000" android:textColor="#ffffffff"
android:text="Golden Gate" />
</merge>
運行程序後在Emulator中顯示的效果是一樣的,可是通過hierarchyviewer查看的UI結構是有變化的,當初多餘的 FrameLayout節點被合併在一起了,或者可以理解爲將merge標籤中的子集直接加到Activity的FrameLayout跟節點下(這裏需要提醒大家注意:所有的Activity視圖的根節點都是FrameLayout)。如果你所創建的Layout並不是用FrameLayout作爲根節點(而是應用LinerLayout等定義root標籤),就不能應用上邊的例子通過merge來優化UI結構。
注:
* <merge />只可以作爲layout的根節點。
* 當需要擴充的layout本身是由merge作爲根節點的話,需要將被導入的layout置於viewGroup中,同時需要設置attachToRoot爲true。