Android 如何去封裝多狀態展示頁面

簡要

  如何做一個多狀態頁面呢?大致分爲網絡異常頁面,無內容頁面,加載頁面,還有成功頁面。還有像網絡錯誤重試功能,平時的話如果每個頁面都去寫一套是非常麻煩的,並且各種狀態切換非常不方便,可能還會出錯。我以前也做過一個多狀態頁面,現在回想起來也過去幾年了,大概是經歷多了,對一些知識又有了新的認知。
多狀態頁面

思路

  我這裏簡單闡述一下我的實現思路,通常情況下,我們整個項目也就兩種類型,一種是展示多狀態頁面類型,一種是固定頁面類型。怎麼去統一實現這種呢,那我們就想到在BaseActivity裏面去封裝。不同的頁面通過一個標誌通知BaseActivity是否需要綁定多狀態頁面。

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View bindLayout = bindLayout();
        if (bindState()) {
            stateLayout = new MultiStateLayout(this);
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(-1, -1);
            bindLayout.setVisibility(View.GONE);
            stateLayout.addView(bindLayout, 0, params);
            setContentView(stateLayout);
        } else {
            setContentView(bindLayout);
        }
    }
    protected boolean bindState() {
        return false;
    }
    protected abstract View bindLayout();

說明:
1、如果具體頁面需要多狀態頁面,重寫bindState()並返回true,這樣在oncreate裏面就會把自己本身的佈局加到多狀態佈局中。
2、 bindLayout()的是具體的佈局

多狀態

  我在多狀態頁面分了網絡異常(包含無網絡)、無數據、loading頁面。我只是大致分了一下。重要是看一下思路,然後根據項目去定製符合項目的多狀態頁面。代碼很簡單,整個我就放下面了。具具體使用一定要修改,如下:

public class MultiStateLayout extends ConstraintLayout {

    public static final int STATE_LOADING = 1;
    public static final int STATE_NET_ERROR = 2;
    public static final int STATE_NO_DATA = 3;
    public static final int STATE_SUCCESS = 4;

    @IntDef({STATE_LOADING, STATE_NET_ERROR,
            STATE_NO_DATA, STATE_SUCCESS})
    @Retention(RetentionPolicy.SOURCE)
    public @interface State {
    }

    private int curState = STATE_LOADING;
    private final MultiStateLayoutBinding binding;

    public MultiStateLayout(@NonNull Context context) {
        super(context);
        binding = MultiStateLayoutBinding.inflate(LayoutInflater.from(context), this, true);
        binding.btnReload.setOnClickListener(v -> {
            if (context instanceof BaseActivity) {
                bindState(STATE_LOADING);
                ((BaseActivity) context).reload();
            }
        });
    }

    public int getState() {
        return this.curState;
    }

    public void bindState(@State int state) {
        if (state == curState) {
            return;
        }
        this.curState = state;
        //加載中的
        binding.pbLoading.setVisibility(this.curState == STATE_LOADING ? VISIBLE : GONE);
        binding.tvLoadingMsg.setVisibility(this.curState == STATE_LOADING ? VISIBLE : GONE);
        //網絡錯誤
        binding.ivNetError.setVisibility(this.curState == STATE_NET_ERROR ? VISIBLE : GONE);
        binding.tvNetErrorMsg.setVisibility(this.curState == STATE_NET_ERROR ? VISIBLE : GONE);
        binding.btnReload.setVisibility(this.curState == STATE_NET_ERROR ? VISIBLE : GONE);
        //無數據
        binding.ivNoData.setVisibility(this.curState == STATE_NO_DATA ? VISIBLE : GONE);
        binding.tvNoDataMsg.setVisibility(this.curState == STATE_NO_DATA ? VISIBLE : GONE);
        //無數據
        binding.ivNoData.setVisibility(this.curState == STATE_NO_DATA ? VISIBLE : GONE);
        binding.tvNoDataMsg.setVisibility(this.curState == STATE_NO_DATA ? VISIBLE : GONE);
        //成功
        View successView = getChildAt(0);
        if (successView != null) {
            successView.setVisibility(this.curState == STATE_SUCCESS ? VISIBLE : GONE);
        }
    }
}

其他

  比如如果想要增加其他狀態,可以在MultiStateLayout中操作,還有各種狀態對應自己項目中對應的狀態類型,目前只是提示思路,還有具體狀態的圖片切換和文本描述,使用的使用可以抽取出來,通過方法的調用去實現。還有BaseFragment的實現,還有一些dialog的實現均可以採用這種方式,相當於對項目做了解耦。

總結

  這裏做一下總結,其中有兩部分組成,第一部分是內部的組成關係,組成關係中最主要的是幾個位運算和幾個參數的意義。第二部分是值的來源和決定因素,onMeasure()方法中值由父類傳遞過來,其值是根據父類的mode和自身的LayoutParams決定。如果還感覺很模糊,不妨自己去寫個例子去驗證一下,這樣可以加深印象,最重要的還是要理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章