Android 讓你的布局飛起來

分類:技術 時間:2017-01-13

xiaoguo.gif

前言

在Android項目開發中一個界面的顯示狀態包括好幾種:內容界面,loading界面,網絡錯誤界面等等;以前開發的時候都是直接把這些界面include到main界面中,然后動態去切換界面,后來發現這樣處理不容易復用到其他項目中,而且在activity中處理這些狀態的顯示和隱藏比較亂,所以就想著能不能封裝一個類來管理這些狀態View的切換。

思路

為了讓View狀態的切換和Activity徹底分離開,必須把這些狀態View都封裝到一個管理類中,然后暴露出幾個方法來實現View之間的切換,因為在不同的項目中可以需要的View也不一樣,所以考慮把管理類設計成builder模式來自由的添加需要的狀態View。

實現

通常一個界面會包括:內容,空數據,異常錯誤,加載,網絡錯誤等5種狀態view,所以我們就設置這5種View的切換

public static final class Builder {    

        private Context context;    
        private int loadingLayoutResId;    
        private int contentLayoutResId;    
        private ViewStub netWorkErrorVs;    
        private ViewStub emptyDataVs;    
        private ViewStub errorVs;    
        private OnShowHideViewListener onShowHideViewListener;    

        public Builder(Context context) {       
            this.context = context;    
        }    

        public Builder loadingView(@LayoutRes int loadingLayoutResId) {    
            this.loadingLayoutResId = loadingLayoutResId;        
            return this;    
        }    

        public Builder netWorkErrorView(@LayoutRes int newWorkErrorId) {    
            netWorkErrorVs = new ViewStub(context);     
            netWorkErrorVs.setLayoutResource(newWorkErrorId);        
            return this;    
        }    

       public Builder emptyDataView(@LayoutRes int noDataViewId) {    
            emptyDataVs = new ViewStub(context);        
            emptyDataVs.setLayoutResource(noDataViewId);       
            return this;   
       }    

       public Builder errorView(@LayoutRes int errorViewId) {        
            errorVs = new ViewStub(context);   
            errorVs.setLayoutResource(errorViewId);        
            return this;    
       }    

      public Builder contentView(@LayoutRes int contentLayoutResId) {       
            this.contentLayoutResId = contentLayoutResId;        
            return this;    
      }    

      public Builder onShowHideViewListener(OnShowHideViewListener onShowHideViewListener) {       
             this.onShowHideViewListener = onShowHideViewListener;        
             return this;    
      }    

      public StatusLayoutManager build() {        
             return new StatusLayoutManager(this);   
      }
}

上面代碼是管理類的builder內部類,總共有7個屬性,loadingLayoutResId和contentLayoutResId代表等待加載和顯示內容的xml文件;netWorkErrorVs,emptyDataVs,errorVs代表另外幾種狀態,那為什么這幾種狀態要用ViewStub,因為在界面狀態切換中loading和內容View都是一直需要加載顯示的,但是其他的3個只有在沒數據或者網絡異常的情況下才會加載顯示,所以用ViewStub來加載他們可以提高性能。

接下來需要把這些View添加到一個根View中返回給Activity,為了方便顯示隱藏這些View,我們在根View中定義一個集合屬性,然后把這些View添加到集合當中管理

/** *  存放布局集合 */
private SparseArraylt;Viewgt; layoutSparseArray = new SparseArray();

這個集合Key為id,Value為View,id為根View類內部自定義的id,通過id找到對應的View來顯示隱藏View,下面通過一個方法來看下它的切換邏輯

/** *  顯示空數據 */
public void showEmptyData() {    
     if(inflateLayout(LAYOUT_EMPTYDATA_ID))      
      showHideViewById(LAYOUT_EMPTYDATA_ID);
}

首先調用inflateLayout方法,方法返回true才會調用下面的方法,

我們來看看這個方法的實現

private boolean inflateLayout(int id) {    
    boolean isShow = true;    
    if(layoutSparseArray.get(id) != null) return isShow;    
    switch (id) {        
       case LAYOUT_NETWORK_ERROR_ID:            
         if(netWorkErrorVs != null) {                
           View view = netWorkErrorVs.inflate();                
           layoutSparseArray.put(id, view);                
           isShow = true;            
         } else {                
           isShow = false;            
         }            
         break;        

       case LAYOUT_ERROR_ID:            
           if(errorVs != null) {               
              View view = errorVs.inflate();                
              layoutSparseArray.put(id, view);                
              isShow = true;            
           } else {                
              isShow = false;           
           }            
           break;        

      case LAYOUT_EMPTYDATA_ID:            
          if(emptyDataVs != null) {                
              View view = emptyDataVs.inflate();                
              layoutSparseArray.put(id, view);                
              isShow = true;            
          } else {                
              isShow = false;            
          }            
          break;    
      }    
      return isShow;
}

方法里面通過id判斷來執行不同的代碼,首先判斷ViewStub是否為空,如果為空就代表沒有添加這個View就返回false,不為空就加載View并且添加到集合當中,然后調用showHideViewById方法顯示隱藏View

private void showHideViewById(int id) {    
    for(int i = 0; i lt; layoutSparseArray.size(); i  ) {        
        int key = layoutSparseArray.keyAt(i);        
        View valueView = layoutSparseArray.valueAt(i);        
        //顯示該view        
        if(key == id) {            
            valueView.setVisibility(View.VISIBLE);            
            if(mOnShowHideListener != null) 
              mOnShowHideListener.onShow(valueView, key);       
         } else {           
             if(valueView.getVisibility() != View.GONE) {     
                 valueView.setVisibility(View.GONE);                
             if(mOnShowHideListener != null) 
                  mOnShowHideListener.onHide(valueView, key);            
         }        
   }    
}}

結束語

至此,核心邏輯和代碼都已經分析完成,想看如何調用和源碼的朋友可以移步至: https://github.com/chenpengfei88/StatusLayout


Tags: 安卓開發

文章來源:http://www.jianshu.com/p/9d53893b3eda


ads
ads

相關文章
ads

相關文章

ad