xiaoguo.gif

preface

In Android project development, the display state of an interface includes several kinds: content interface, loading interface, network error interface, etc. In the past, we used to include these interfaces directly into the main interface, and then dynamically switch the interface. Later, we found that such a process is not easy to reuse to other projects, and it is messy to deal with the display and hiding of these states in the activity, so WE thought we could encapsulate a class to manage these state View switches.

Train of thought

In order to completely separate the View state switch from the Activity, we must encapsulate these state views into a management class, and then expose several methods for switching between views, because different projects may need different views. So consider designing the admin class as a Builder mode to add the required state View from scratch.

implementation

Usually a interface will include: content, empty data, abnormal error, load, network error and other five state view, so we set the switch of these five views

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); }}Copy the code

LoadingLayoutResId and contentLayoutResId represent XML files waiting to be loaded and displayed; NetWorkErrorVs, emptyDataVs, errorVs represents other states, why use ViewStub for these states, because loading and View content always need to be loaded and displayed during interface state switching. But the other three will only load the display if there is no data or a network exception, so using the ViewStub to load them can improve performance.

We then need to add these views to a root View to return to the Activity. To make it easier to hide and display these views, we define a collection property in the root View, and then add these views to the collection to manage

/** * store layout set */
private SparseArray<View> layoutSparseArray = new SparseArray(a);Copy the code

This collection Key is ID, Value is View, and ID is the internal self-defined ID of the root View class. Find the corresponding View by ID to display the hidden View. Here is a method to look at its switching logic

/** * displays null data */
public void showEmptyData(a) {    
     if(inflateLayout(LAYOUT_EMPTYDATA_ID))      
      showHideViewById(LAYOUT_EMPTYDATA_ID);
}Copy the code

The inflateLayout method is called first and returns true to invoke the following method. Let’s look at the implementation of this method

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;
}Copy the code

The showHideViewById method is used to execute different code. First, check whether the ViewStub is empty. If it is empty, the View is not added and false is returned

private void showHideViewById(int id) {    
    for(int i = 0; i < layoutSparseArray.size(a); i++) {int key = layoutSparseArray.keyAt(i);        
        View valueView = layoutSparseArray.valueAt(i);        
        // Display the 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); }}}}Copy the code

conclusion

At this point, the core logic and code have been analyzed, want to see how to call and source code friends can go to: github.com/chenpengfei…