布局技巧
在Android開發過程中,我們會遇到很多的問題,隨著UI界面越來越多,布局的重復性、復雜度也隨之增加,所幸的是,Android官方也給出了幾個對布局進行優化的方法,下面根據自己的理解對官方所介紹的方法進行分享,有錯誤的地方希望大家進行留言,相互交流。
輕量布局之ViewStub標簽分析
ViewStub是一個輕量級View,也是一個初始化不做任何事情的View,但是之后我們可以加載入一個布局文件,在慢加載時View中做占位符而已。比如我們根據條件在動態加載View或者某個布局時,最通常就是把可能用到的View都寫在布局上,然后可見性都設置為View.GONE 。之后在代碼中動態更改其可見性,雖然操作簡單,但是耗費資源,因為View.GONE在inflate布局仍會inflate,仍會創建對象,會被實例化,會被設置屬性。而我推薦做法是用android.view.ViewStub,它指定一個布局時會被inflate和實例化,但是不占布局位置,占用資源少。當ViewStub所指向的布局被設置為可見,或者是調用了ViewStub.inflate()時,ViewStub所在的布局才會進行inflate之后實例化,然后ViewStub的布局屬性傳給它所指定的布局。當然,ViewStub的使用還是有缺點的,并不是任何時候都可以用。
ViewStub使用限制:
- ViewStub只能被inflate一次,之后ViewStub對象就會被置為空,就從view層次上移除了,也就是說它所指定的布局被inflate之后,就不能再通過ViewStub去控制這個布局了;
- ViewStub只能用來inflate一個布局文件,而不能是某一個具體的View,這時我們要做的是可以將View寫在一個布局中;
- ViewStub目前還不支持<merge/>標簽。
考慮到以上ViewStub的特點,再結合我自身的開發過程中,可以考慮到使用的ViewStub時主要有以下的情形:
- 當需要在運行時不止一次的顯示和隱藏某一個布局時,ViewStub不可用,因為它只能夠inflate一次,之后就會被置為空。這時只能采用View的可見性來控制了。
- 想要控制的是一個布局文件,而非View,ViewStub指定的是一個布局id,而非一個View對象。
當在使用ViewStub的布局屬性時,某些屬性是加在ViewStub上面,而不是加在實際的布局上面,這樣才會起作用。而ViewStub的屬性在inflate之后會都傳給相應的布局。其中有個屬性android:inflatedId 指是的可以使用它來重寫包含布局文件的根元素的id。而在ViewStub上設定的layout_* 參數將會應用到包含的布局文件的頂部。
重用布局之Include標簽分析
我們在做項目過程中,用得最多的標簽應該是include,它是為了解決重復定義相同布局的問題。例如你有五個界面,這五個界面頂部都有一個相同的一個返回按妞和一個文本控件,若在不使用include情況下你在每個界面都需要重新在xml里面寫相同的布局,這樣造成工作量重復。而當我們使用了include標簽,就可以把多次使用的這個布局獨立成一個xml文件,之后在需要的地方通過include標簽進行引用,自己不用再重復寫一遍。示例如下:
my_title_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/my_title_parent_id"
android:layout_height="wrap_content" >
<ImageButton
android:id="@+id/back_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/title_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@+id/back_btn"
android:gravity="center"
android:text="我的title"
android:textSize="18sp" />
</RelativeLayout>
而在include布局文件中進行設置:
<?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" >
<include
android:id="@+id/my_title_ly"
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="@layout/my_title_layout" />
<!-- 代碼省略 -->
</LinearLayout>
注意事項
- 使用include最常見是找不到findViewById查找不到目標控件,應通過include的id來獲取目標布 局中子控件,當include指定了id,而你的layout也指定了id,則你的layout中的id會被覆蓋。這里來說,具體使用的id應該是my_title_ly,而不應該是原先的my_title_parent_id
- 其次,在include標簽中所有的android:layout_*都是有效的,但前提是必須要寫layout_width和layout_height兩個屬性
- 布局中可以包含兩個相同的include標簽,引用時可以使用不同的include的id進行查找即可
減少布局層級之merge標簽分析
merge標簽可以刪除多余的層級,優化UI。其多用于替換FrameLayout或者當一個布局包含另一個時,它主要消除視圖層次結構中多余的視圖組。主要使用在當一個子視圖不需要指定任何針對父視圖的布局屬性時,例如你的主布局文件是垂直布局,引入了一個垂直布局的include并且引入的布局沒有針對父視圖屬性時,這時如果include布局使用的LinearLayout就會沒有意義,使用的話會重復有兩個LinearLayout布局,這樣的話會增多無必要的UI層次的布局,這時就可以用<merge>標簽進行優化成一個LinearLayout
注意事項
- 其標簽只可用作xml中layout布局文件的根節點,如果擴充的layout布局本身是由merge作為根節點的話,則在代碼中需要將被導入的layout布局文件置于ViewGroup中,同時需要設置attachToRoot為True
總結
布局優化的分享到此就結束了,在Android開發的過程中,只要我們多使用這些布局標簽,會使得我們的布局看起來更加的專業。有問題的朋友可以留言一起探討。