前言
在Android開發(fā)中,View的展示是最貼近用戶,也是最能直觀展示產(chǎn)品的手段。除了美觀的界面之外,View的性能也是很重要的。
而View是由一層一層的View嵌套而成,形成類似于樹的層級結(jié)構(gòu),通過層級結(jié)構(gòu)展示View。View樹的深度決定了展示的流暢度,深度越深,繪制需要的時間也就越長,體驗效果越差。優(yōu)化布局從另一方面說,也是就是想辦法降低View樹的深度,提高加載速度,達(dá)到性能調(diào)優(yōu)。
下面介紹三個日常開發(fā)中可能會使用到的布局優(yōu)化標(biāo)簽,以及一個實際開發(fā)中可能碰到的問題和解決方式。
代碼比較簡潔有的甚至沒有,但是標(biāo)簽本來就是一些工具而已,把最后實戰(zhàn)方面的看懂了,汲取了這種封裝的思想,我寫這篇文章的目的就達(dá)到了。
include標(biāo)簽
當(dāng)一個View需要復(fù)用的時候,采取<include/>標(biāo)簽可以減少重復(fù)布局的使用。
使用場景
<include/>標(biāo)簽可能接觸的都比較多,在Android布局中,很多時候會碰到需要使用相同的布局,例如每個Activity的TitleBar,評論框等。這個時候可以使用<include/>標(biāo)簽。
步驟
- 新建一個title.xml,在里面寫好對應(yīng)的布局文件的實現(xiàn),
- 在需要使用的地方使用
other code...
<include layout="@layout/titlebar"/>
ViewStub標(biāo)簽
<ViewStub/>是一種不可見且大小為0的View,它的主要作用是當(dāng)你不需要的時候不加載,當(dāng)你需要的時候才去加載這個布局。也就是說<ViewStub/>實現(xiàn)了View的延遲加載。
需要注意的是:當(dāng)ViewStub設(shè)置為可見或者被inflate之后,就會填充布局資源,之后會被填充的View給替代,和普通的View沒有任何區(qū)別。
使用場景
錯誤圖,也就是當(dāng)數(shù)據(jù)錯誤的時候需要展示的一些圖片和提示信息。但是這個錯誤圖又不是每次都會顯示,大部分情況下都是正常顯示,只有當(dāng)出現(xiàn)一些問題的時候才會顯示錯誤圖,這個時候就可以使用<ViewStub/>
步驟
- 在需要使用的地方使用<ViewStub/>標(biāo)簽
<?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" >
<ViewStub
android:id="@+id/network_error_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/network_error"
android:inflatedId="@+id/error_view"/>
</RelativeLayout>
2.新建network_error.xml文件
比如說一個ImageView
other code...
3.代碼中使用
ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout);
networkErrorView = stub.inflate();
在ViewStub中:
android:layout表示當(dāng)需要展示的時候?qū)故镜腖ayout
android:inflatedId表示當(dāng)在Java代碼中調(diào)用ViewStub的inflate()或者setVisibility()方法返回的Id,也是就填充圖Id。
merge標(biāo)簽
減少View樹深度的利器
使用場景
在一般情況下,比如在ViewPager或者RecyclerView中,我們在每個Item的根布局中往往是使用LinearLayout或者其他的ViewGroup。如果有的時候我們只需要展示一張照片或者單獨文字,這樣就很不值得,因為每個ViewGroup對應(yīng)的就在View樹中又往深了一步。這個時候使用<merge/>標(biāo)簽來減少View樹的深度再好不過。
merge標(biāo)簽可用于兩種典型情況:
- 布局頂結(jié)點是FrameLayout且不需要設(shè)置background或padding等屬性,可以用merge代替,因為Activity內(nèi)容視圖的parent view就是個FrameLayout,所以可以用merge消除只剩一個。
- 某布局作為子布局被其他布局include時,使用merge當(dāng)作該布局的頂節(jié)點,這樣在被引入時頂結(jié)點會自動被忽略,而將其子節(jié)點全部合并到主布局中。
步驟
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_above="@+id/text"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_alignParentBottom="true"
android:text="@string/app_name" />
優(yōu)化實戰(zhàn)例子
需求
在開發(fā)中有的時候TitleBar需要實現(xiàn)各種不同的布局,比如這個Activity需要一個TextView,這個Activity可能需要一個EditText,或者各種自定義View。
這個時候如果每個Activity的TItleBar都對應(yīng)寫新的布局,這樣無疑加大了工作量。
思路(!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
我們可以將這個TitleBar很Activity邏輯分離,抽出布局作為titlebar.xml,里面包含了各種View。
然后再抽出一個TitleBar.class類,組合放在BaseActivity中。共通的東西可以在BaseActivity實現(xiàn)(比如左前方返回按鈕),不同的東西放在子類中實現(xiàn)(EditText或者自定義View),靈活使用ViewStud實現(xiàn)延遲加載,merge減少層級。
代碼結(jié)構(gòu)可以使用Builder模式實現(xiàn),注意<ViewStub/>和<merge/>的使用,注意空指針以及容錯,這樣就實現(xiàn)了一個標(biāo)準(zhǔn)TitleBar控件。
后話
還有一些很好的工具可以實現(xiàn)布局優(yōu)化,比如Android Studio的lint,TraceView,HierarchyViewer,手機自帶的開發(fā)人員選項中的工具等等等。
規(guī)范的布局代碼加上工具檢測,布局優(yōu)化就OK了。