簡要
如何做一個多狀態頁面呢?大致分爲網絡異常頁面,無內容頁面,加載頁面,還有成功頁面。還有像網絡錯誤重試功能,平時的話如果每個頁面都去寫一套是非常麻煩的,並且各種狀態切換非常不方便,可能還會出錯。我以前也做過一個多狀態頁面,現在回想起來也過去幾年了,大概是經歷多了,對一些知識又有了新的認知。
多狀態頁面
思路
我這裏簡單闡述一下我的實現思路,通常情況下,我們整個項目也就兩種類型,一種是展示多狀態頁面類型,一種是固定頁面類型。怎麼去統一實現這種呢,那我們就想到在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決定。如果還感覺很模糊,不妨自己去寫個例子去驗證一下,這樣可以加深印象,最重要的還是要理解。