佈局優化之ViewStub、Include、merge使用分析

Mz_Chris發表於2015-01-31

佈局技巧

在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使用限制:

  1. ViewStub只能被inflate一次,之後ViewStub物件就會被置為空,就從view層次上移除了,也就是說它所指定的佈局被inflate之後,就不能再通過ViewStub去控制這個佈局了;
  2. ViewStub只能用來inflate一個佈局檔案,而不能是某一個具體的View,這時我們要做的是可以將View寫在一個佈局中;
  3. ViewStub目前還不支援標籤。

考慮到以上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開發的過程中,只要我們多使用這些佈局標籤,會使得我們的佈局看起來更加的專業。有問題的朋友可以留言一起探討。

相關文章