天天看點

ViewStub用法

在開發應用程式的時候,經常會遇到這樣的情況,會在運作時動态根據條件來決定顯示哪個View或某個布局。那麼最通常的想法就是把可能用到的View都寫在上面,先把它們的可見性都設為View.GONE,然後在代碼中動态的更改它的可見性。這樣的做法的優點是邏輯簡單而且控制起來比較靈活。但是它的缺點就是,耗費資源。雖然把View的初始可見View.GONE但是在Inflate布局的時候View仍然會被Inflate,也就是說仍然會建立對象,會被執行個體化,會被設定屬性。也就是說,會耗費記憶體等資源。

      但ViewStub也不是萬能的,下面總結下ViewStub能做的事兒和什麼時候該用ViewStub,什麼時候該用可見性的控制。

     首先來說說ViewStub的一些特點:

         1. ViewStub隻能Inflate一次,之後ViewStub對象會被置為空。按句話說,某個被ViewStub指定的布局被Inflate後,就不會夠再通過ViewStub來控制它了。

         2. ViewStub隻能用來Inflate一個布局檔案,而不是某個具體的View,當然也可以把View寫在某個布局檔案中。

     基于以上的特點,那麼可以考慮使用ViewStub的情況有:

         1. 在程式的運作期間,某個布局在Inflate後,就不會有變化,除非重新啟動。

              因為ViewStub隻能Inflate一次,之後會被置空,是以無法指望後面接着使用ViewStub來控制布局。是以當需要在運作時不止一次的顯示和 隐藏某個布局,那麼ViewStub是做不到的。這時就隻能使用View的可見性來控制了。

         2. 想要控制顯示與隐藏的是一個布局檔案,而非某個View。

              因為設定給ViewStub的隻能是某個布局檔案的Id,是以無法讓它來控制某個View。

     是以,如果想要控制某個View(如Button或TextView)的顯示與隐藏,或者想要在運作時不斷的顯示與隐藏某個布局或View,隻能使用View的可見性來控制。

下面來看一個執行個體

在這個例子中,要顯示二種不同的布局,一個是用TextView顯示一段文字,另一個則是用ImageView顯示一個圖檔。這二個是在onCreate()時決定是顯示哪一個,這裡就是應用ViewStub的最佳地點。

先來看看布局,一個是主布局,裡面隻定義二個ViewStub,一個用來控制TextView一個用來控制ImageView,另外就是一個是為顯示文字的做的TextView布局,一個是為ImageView而做的布局:

<a></a>

為TextView的布局:

為ImageView的布局:

下面來看代碼,決定來顯示哪一個,隻需要找到相應的ViewStub然後調用其infalte()就可以獲得相應想要的布局:

運作結果:

使用的時候的注意事項:

1. 某些布局屬性要加在ViewStub而不是實際的布局上面,才會起作用,比如上面用的android:layout_margin*系列屬性,如果加在 TextView上面,則不會起作用,需要放在它的ViewStub上面才會起作用。而ViewStub的屬性在inflate()後會都傳給相應的布 局。 1.ViewStub之是以常稱之為“延遲化加載”,是因為在教多數情況下,程式 無需顯示ViewStub所指向的布局檔案,隻有在特定的某些較少條件下,此時ViewStub所指向的布局檔案才需要被inflate,且此布局檔案直 接将目前ViewStub替換掉,具體是通過viewStub.infalte()或 viewStub.setVisibility(View.VISIBLE)來完成; 2.正确把握住ViewStub的應用場景非常重要,正如如1中所描述需求場景下,使用ViewStub可以優化布局; 3.對ViewStub的inflate操作隻能進行一次,因為inflate的 時候是将其指向的布局檔案解析inflate并替換掉目前ViewStub本身(由此展現出了ViewStub“占位符”性質),一旦替換後,此時原來的 布局檔案中就沒有ViewStub控件了,是以,如果多次對ViewStub進行infalte,會出現錯誤資訊:ViewStub must have a non-null ViewGroup viewParent。 4.3中所講到的ViewStub指向的布局檔案解析inflate并替換掉目前 ViewStub本身,并不是完全意義上的替換(與include标簽還不太一樣),替換時,布局檔案的layout params是以ViewStub為準,其他布局屬性是以布局檔案自身為準。 5.ViewStub本身是不可見的,對 ViewStub setVisibility(..)與其他控件不一樣,ViewStub的setVisibility 成View.VISIBLE或INVISIBLE如果是首次使用,都會自動inflate其指向的布局檔案,并替換ViewStub本身,再次使用則是相 當于對其指向的布局檔案設定可見性。 viewStub中加載layout的代碼是 public View inflate() {       final ViewParent viewParent = getParent();// 擷取目前view的父view,用于擷取需要加載的layout的index       if (viewParent != null &amp;&amp; viewParent instanceof ViewGroup) {           if (mLayoutResource != 0) {               final ViewGroup parent = (ViewGroup) viewParent;               final LayoutInflater factory;               if (mInflater != null) {                   factory = mInflater;               } else {                   factory = LayoutInflater.from(mContext);               }               final View view = factory.&lt;strong&gt;&lt;span style="font-size:14px;color:#ff0000;"&gt;inflate&lt;/span&gt;&lt;/strong&gt;(mLayoutResource, parent, false);// 擷取需要加載的layout               if (mInflatedId != NO_ID) {                   view.setId(mInflatedId);               final int index = parent.indexOfChild(this);               parent.removeViewInLayout(this);// 删除之前加載的view               final ViewGroup.LayoutParams layoutParams = getLayoutParams();               if (layoutParams != null) {                   parent.addView(view, index, layoutParams);                   parent.&lt;strong&gt;&lt;span style="font-size:14px;color:#ff0000;"&gt;addView&lt;/span&gt;&lt;/strong&gt;(view, index);// 添加view               mInflatedViewRef = new WeakReference&lt;View&gt;(view);               if (mInflateListener != null) {                   mInflateListener.onInflate(this, view);               return view;           } else {               throw new IllegalArgumentException("ViewStub must have a valid layoutResource");           }       } else {           throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");       }   }      本文轉自 一點點征服   部落格園部落格,原文連結: http://www.cnblogs.com/ldq2016/p/5386397.html ,如需轉載請自行聯系原作者

繼續閱讀