前言
在Android開發(fā)中郊尝,View的展示是最貼近用戶,也是最能直觀展示產(chǎn)品的手段。除了美觀的界面之外杖虾,View的性能也是很重要的。
而View是由一層一層的View嵌套而成媒熊,形成類似于樹的層級結(jié)構(gòu)奇适,通過層級結(jié)構(gòu)展示View。View樹的深度決定了展示的流暢度芦鳍,深度越深嚷往,繪制需要的時間也就越長,體驗效果越差柠衅。優(yōu)化布局從另一方面說皮仁,也是就是想辦法降低View樹的深度,提高加載速度菲宴,達到性能調(diào)優(yōu)贷祈。
下面介紹三個日常開發(fā)中可能會使用到的布局優(yōu)化標簽,以及一個實際開發(fā)中可能碰到的問題和解決方式喝峦。
代碼比較簡潔有的甚至沒有势誊,但是標簽本來就是一些工具而已,把最后實戰(zhàn)方面的看懂了谣蠢,汲取了這種封裝的思想粟耻,我寫這篇文章的目的就達到了。
include標簽
當一個View需要復用的時候漩怎,采取<include/>標簽可以減少重復布局的使用勋颖。
使用場景
<include/>標簽可能接觸的都比較多,在Android布局中勋锤,很多時候會碰到需要使用相同的布局饭玲,例如每個Activity的TitleBar,評論框等叁执。這個時候可以使用<include/>標簽茄厘。
步驟
- 新建一個title.xml,在里面寫好對應的布局文件的實現(xiàn)谈宛,
- 在需要使用的地方使用
other code...
<include layout="@layout/titlebar"/>
ViewStub標簽
<ViewStub/>是一種不可見且大小為0的View次哈,它的主要作用是當你不需要的時候不加載,當你需要的時候才去加載這個布局吆录。也就是說<ViewStub/>實現(xiàn)了View的延遲加載窑滞。
需要注意的是:當ViewStub設(shè)置為可見或者被inflate之后,就會填充布局資源,之后會被填充的View給替代哀卫,和普通的View沒有任何區(qū)別巨坊。
使用場景
錯誤圖,也就是當數(shù)據(jù)錯誤的時候需要展示的一些圖片和提示信息此改。但是這個錯誤圖又不是每次都會顯示趾撵,大部分情況下都是正常顯示,只有當出現(xiàn)一些問題的時候才會顯示錯誤圖共啃,這個時候就可以使用<ViewStub/>
步驟
- 在需要使用的地方使用<ViewStub/>標簽
<?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表示當需要展示的時候?qū)故镜腖ayout
android:inflatedId表示當在Java代碼中調(diào)用ViewStub的inflate()或者setVisibility()方法返回的Id占调,也是就填充圖Id。
merge標簽
減少View樹深度的利器
使用場景
在一般情況下移剪,比如在ViewPager或者RecyclerView中究珊,我們在每個Item的根布局中往往是使用LinearLayout或者其他的ViewGroup。如果有的時候我們只需要展示一張照片或者單獨文字纵苛,這樣就很不值得苦银,因為每個ViewGroup對應的就在View樹中又往深了一步。這個時候使用<merge/>標簽來減少View樹的深度再好不過赶站。
merge標簽可用于兩種典型情況:
- 布局頂結(jié)點是FrameLayout且不需要設(shè)置background或padding等屬性幔虏,可以用merge代替,因為Activity內(nèi)容視圖的parent view就是個FrameLayout贝椿,所以可以用merge消除只剩一個想括。
- 某布局作為子布局被其他布局include時,使用merge當作該布局的頂節(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都對應寫新的布局位迂,這樣無疑加大了工作量。
思路(!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)
我們可以將這個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)了一個標準TitleBar控件。
后話
還有一些很好的工具可以實現(xiàn)布局優(yōu)化柒竞,比如Android Studio的lint,TraceView,HierarchyViewer,手機自帶的開發(fā)人員選項中的工具等等等。
規(guī)范的布局代碼加上工具檢測播聪,布局優(yōu)化就OK了朽基。