引言
1.我們在日常開發中經常會遇到數據加載需要網絡請求的場景,我們通常的做法是用系統提供的ProgressDialog組件
(顯示等待進度的dialog) 但是會有一個不友好的地方(假如網絡出異常了,此時頁面沒有填充數據。此時就要控制頁面
內一些交互操作,這樣界面中就會多出一大串邏輯控制代碼),有一種解決方案解決上述的缺點,就是界面內部用一個進度條
遮蓋內容頁面,用邏輯進行控制請求中、請求失敗、無數據等幾種狀態,但是一個app裏面有辣麼多的界面都是這種需求,
要是每個界面都這樣寫豈不很重複繁瑣。如何簡化呢,封裝起來(*@ο@*) 哇~
2.今天給大家介紹個自定義view組件來解決此問題(ui的效果根據大家自己的需求 自行定製哈)
先來張動態圖=-=
需求點
1.這個view需要有一個方法來控制各個狀態的切換
2.可以定製加載進度條的狀態
3.可以定製無數據的頁面
4.加載失敗可以提供刷新操作
實現思路
既然是自定義view,api就得儘量簡潔好理解嘛,我所設想的api
//根據場景切換各個狀態State各種狀態的枚舉(往下看)
public void notifyDataChanged(State state)
//數據加載失敗提供重試的回調
public void setOnRetryListener(OnRetryListener listener)
//設置數據爲null顯示的view
public void setEmptyView(View view)
//重試回調的接口0
public interface OnRetryListener {
void onRetry();
}
刷新的各種狀態
public enum State {
ing, error, done, empty
}
api是不是很簡單^_^
接下來貼整個類的代碼(一種不到100行代碼)
package cn.wei.library.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import cn.wei.library.R;
/**
* LoadingView解決了請求網絡數據時ui顯示的三種狀態
* 分別爲加載中,加載失敗,無數據
* email: [email protected]
* @author qinwei create by 2015/10/28
*/
public class LoadingView extends FrameLayout implements OnClickListener {
private View empty;
private View error;
private View loading;
private State state;
private OnRetryListener listener;
public interface OnRetryListener {
void onRetry();
}
public enum State {
ing, error, done, empty
}
public LoadingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initializeView(context);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
initializeView(context);
}
public LoadingView(Context context) {
super(context);
initializeView(context);
}
private void initializeView(Context context) {
LayoutInflater.from(context).inflate(R.layout.widget_loading_view, this);
empty = findViewById(R.id.empty);
loading = findViewById(R.id.loading);
error = findViewById(R.id.error);
setOnClickListener(this);
notifyDataChanged(State.ing);
}
public void notifyDataChanged(State state) {
this.state = state;
switch (state) {
case ing:
setVisibility(View.VISIBLE);
loading.setVisibility(View.VISIBLE);
empty.setVisibility(View.GONE);
error.setVisibility(View.GONE);
break;
case empty:
setVisibility(View.VISIBLE);
loading.setVisibility(View.GONE);
empty.setVisibility(View.VISIBLE);
error.setVisibility(View.GONE);
break;
case error:
setVisibility(View.VISIBLE);
loading.setVisibility(View.GONE);
empty.setVisibility(View.GONE);
error.setVisibility(View.VISIBLE);
break;
case done:
setVisibility(View.GONE);
break;
default:
break;
}
}
public void setOnRetryListener(OnRetryListener listener) {
this.listener = listener;
}
public void setEmptyView(View view) {
empty.removeAllViews();
empty.addView(view);
}
@Override
public void onClick(View v) {
if (listener != null && state == State.error) {
listener.onRetry();
}
}
}
widget_loading_view.xml佈局:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="無數據" />
</LinearLayout>
<LinearLayout
android:id="@+id/loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<!---mWidgetContainerView-->
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/error"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_load_err" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="網絡出問題啦"
android:textColor="#8e9fa5"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="點擊屏幕,重新加載"
android:textColor="#8e9fa5" />
</LinearLayout>
</merge>
LoadingView如何使用呢
1.xml佈局引入LoadingView
<cn.wei.library.widget.LoadingView
android:id="@+id/mLoadingView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
2.activity或者fragment裏面
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ViewSwitcher;
import cn.wei.library.widget.EmptyView;
import cn.wei.weilibrary.R;
import cn.wei.weilibrary.base.BaseTitleActivity;
public class EmptyViewActivity extends BaseActivity implements EmptyView.OnRetryListener {
private ViewSwitcher mViewSwitcher;
private EmptyView mEmptyView;
@Override
protected void setContentView() {
setContentView(R.layout.activity_empty_view);
}
@Override
protected void initializeData() {
setTitle("EmptyView");
mLoadingView= (LoadingView) findViewById(R.id.mEmptyView);
mLoadingView.setOnRetryListener(this);
mLoadingView.notifyDataChanged(LoadingView.State.ing);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_emtyp_view, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_nodata:
mLoadingView.notifyDataChanged(LoadingView.State.empty);
break;
case R.id.action_loading:
mLoadingView.notifyDataChanged(LoadingView.State.ing);
break;
case R.id.action_err:
mLoadingView.notifyDataChanged(LoadingView.State.error);
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onRetry() {
mLoadingView.notifyDataChanged(LoadingView.State.ing);
}
}
嘿嘿還差個BaseActivity基類(關於在base類的講解,以後單獨出一篇文章解釋)給大家補上
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
/**
* 結構化activity的代碼
* 方法調用順序爲setContentView()->initializeView()-> initializeData();
*/
public abstract class BaseActivity extends AppCompatActivity {
protected String TAG = this.getClass().getSimpleName();
@Override
protected void onCreate(Bundle saveInstance) {
super.onCreate(saveInstance);
setContentView();
initializeView();
initializeData();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* 1. 設置佈局
*/
protected abstract void setContentView();
/**
* 2. 初始化佈局
*/
protected abstract void initializeView();
/**
* 3. 初始化ui數據
*/
protected abstract void initializeData();
}
是不是很簡單呢,https://github.com/qinweiforandroid/LoadingView
結束語
最近纔開始寫博客,如果文章裏有什麼不對的地方還請大家斧正!