MVP + SmartRefreshLayout +RecylerView 列表基類的封裝(初級版)
前言:
最近在專案中引入了SmartRefreshLayout (github地址)智慧重新整理控制元件,支援所有的View(AbsListView,RecyclerView,WebView .... View)和多層巢狀的檢視結構。使用更簡單,強大。在我們專案中,存在多個下拉重新整理的控制元件(XRecylerView、TwinklingRefreshLayout),效果較混亂,不夠統一。程式碼相似度高,重複程式碼較多。為了提高程式碼的複用性、減少重複的程式碼的編寫,將公共的邏輯進行抽取(如設定標題欄、無網路、資料空介面、上拉重新整理、下拉載入、設定adapter、設定LayoutManager、設定ItemDecoration等),故初步封裝了一個基類。
封裝思路:
一、通用列表Activity主要功能分析:
下拉重新整理、上拉載入更多、網路異常處理、空資料介面處理、Activity 標題欄設定、返回頂部按鈕設定、RecylerView LayoutManager設定、RecylerView Adapter設定、RecylerView ItemDecoration設定。
二、程式碼編寫分析:
抽取公有的程式碼,父類進行預設實現,子類可以重寫定製。減少重複程式碼的編碼,讓開發列表介面變得更簡單高效。
程式碼實現:
1、佈局程式碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--設定activity Title標題-->
<LinearLayout
android:id="@+id/ll_base_list_refresh_title_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<android.support.design.widget.CoordinatorLayout
android:id="@+id/cl_base_list_content_root"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:elevation="2dp">
<!--可以跟隨上下滑動顯示隱藏的頭部局-->
<!--scroll|snap 滑動到頂部才顯示出來-->
<!--app:layout_scrollFlags="scroll|snap"-->
<!--scroll|enterAlways|snap 往上滑就顯示出來-->
<!--app:layout_scrollFlags="scroll|enterAlways|snap"-->
<LinearLayout
android:id="@+id/ll_base_list_scroll_top_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/common_white_color"
android:orientation="vertical"
app:layout_scrollFlags="scroll|enterAlways|snap"/>
</android.support.design.widget.AppBarLayout>
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_base_list_refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:srlEnableHeaderTranslationContent="true"
app:srlEnableLoadmore="true"
app:srlEnableRefresh="true">
<android.support.v7.widget.RecyclerView
android:id="@+id/rcy_base_list_recylerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/common_white_color"
/>
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
<!--新增右下角一鍵置頂按鈕-->
<include layout="@layout/inc_to_top"/>
<!--網路異常的介面-->
<include
android:id="@+id/view_base_list_no_net_root"
layout="@layout/common_no_net_layout"
android:visibility="gone"/>
<!--未有資料載入為空顯示的空介面-->
<LinearLayout
android:id="@+id/ll_base_list_empty_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/common_white_color"
android:orientation="vertical"
android:visibility="gone"/>
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
2、java程式碼:
public abstract class BaseListRefreshActivity<V extends BaseView, P extends BasePresenter<V>, T extends RecyclerView.Adapter> extends AppBaseMVPActivity<V, P> {
private LinearLayout mLlTitleTopRoot, mLlScrollTopRoot, mLlEmptyRoot;
private View mTitleView, mTopFixedView, mTopScrollView, mEmptyView, mNotNetRoot;
private Button mBtnNoNetReload;
private ImageView mImgTop;
private CoordinatorLayout mClContentRoot;
private RecyclerView mRecylerView;
private SmartRefreshLayout mRefreshLayout;
private RecyclerView.ItemDecoration mDefaultItemDecoration;
private RecyclerView.LayoutManager mDefaultLayoutManager;
public Context mContext;
public LayoutInflater mInflater;
private T mAdapter;
public T getAdapter() {
return mAdapter;
}
public SmartRefreshLayout getSmartRefreshLayout() {
return mRefreshLayout;
}
public RecyclerView getRecylerView() {
return mRecylerView;
}
public RecyclerView.ItemDecoration getDefaultItemDecoration() {
return mDefaultItemDecoration;
}
public RecyclerView.LayoutManager getDefaultLayoutManager() {
return mDefaultLayoutManager;
}
public View getTitleView() {
return mTitleView;
}
public View getTopFixedView() {
return mTopFixedView;
}
public View getTopScrollView() {
return mTopScrollView;
}
public View getEmptyView() {
return mTopScrollView;
}
@Override
public int getLayoutResId() {
return R.layout.activity_base_list_refresht;
}
@Override
public void initData() {
mContext = this;
mInflater = LayoutInflater.from(this);
}
@Override
public void initView(Bundle savedInstanceState) {
findId2View(); // 找到View
handleTitleTopEmptyView(); // 處理標題欄、空介面View
handleNotNetReload(); // 處理無網路,重新載入
handleGoTopClick(); // 處理返回底部按鈕的點選事件
initSmartRefreshLayout(); // 初始化設定SmartRefreshLayout重新整理控制元件
initRefreshLayoutSetting(mRefreshLayout); // 提供該方法,方便子類更改SmartRefreshLayout重新整理控制元件的設定
setDefaultRecylerView(); // 設定RecylerView
hideGoTopIcon(); // 隱藏返回頂部按鈕
showNormalContentView(); // 顯示正常內容的佈局
loadDataFromServer(true); // 請求伺服器資料
}
/**
* 提供初始化佈局管理器的方法,子類可重寫,預設實現線性佈局
*
* @return LayoutManager
*/
protected RecyclerView.LayoutManager initLayoutManager() {
return new LinearLayoutManager(mContext);
}
/**
* 提供初始化 ItemDecoration的方法,子類可重寫,預設實現LinearVerItemDecoration
*
* @return RecyclerView.ItemDecoration
*/
protected RecyclerView.ItemDecoration initItemDecoration() {
return new LinearVerItemDecoration();
}
/**
* 通過id找到View
*/
private void findId2View() {
mLlTitleTopRoot = findView(R.id.ll_base_list_refresh_title_root);
mClContentRoot = findView(R.id.cl_base_list_content_root);
mLlScrollTopRoot = findView(R.id.ll_base_list_scroll_top_root);
mRecylerView = findView(R.id.rcy_base_list_recylerView);
mRefreshLayout = findView(R.id.srl_base_list_refreshLayout);
mImgTop = findView(R.id.btn_toTop);
// 設定資料為空時顯示的空佈局
mLlEmptyRoot = findView(R.id.ll_base_list_empty_root);
// 無網路佈局
mNotNetRoot = findView(R.id.view_base_list_no_net_root);
mBtnNoNetReload = findView(R.id.refresh_again);
}
/**
* 處理新增標題、頂部View
*/
private void handleTitleTopEmptyView() {
// 新增 Activity 標題欄
mTitleView = initTitleView(mInflater, mLlTitleTopRoot);
if (mTitleView != null) {
mLlTitleTopRoot.addView(mTitleView);
}
// 新增 顯示在標題欄下面的View
mTopFixedView = initTopFixedView(mInflater, mLlTitleTopRoot);
if (mTopFixedView != null) {
mLlTitleTopRoot.addView(mTopFixedView);
}
// 新增可以隨手勢上下滑動顯隱的View
mTopScrollView = initTopScrollView(mInflater, mLlScrollTopRoot);
if (mTopScrollView != null) {
mLlScrollTopRoot.addView(mTopScrollView);
}
// 新增資料為空時顯示的空介面
mEmptyView = initEmptyView(mInflater, mLlEmptyRoot);
if (mEmptyView != null) {
mLlEmptyRoot.addView(mEmptyView);
}
}
/**
* 初始化標題欄,子類進行實現
*
* @param inflater
* @param titleParent
* @return
*/
protected abstract View initTitleView(LayoutInflater inflater, LinearLayout titleParent);
/**
* 初始化 空介面,子類進行實現
*
* @param inflater
* @param emptyParent
* @return
*/
protected abstract View initEmptyView(LayoutInflater inflater, LinearLayout emptyParent);
/**
* 網路異常 重新載入按鈕點選回撥監聽方法
*/
protected abstract void onNoNetReload();
/**
* recylerView 滑動事件回撥監聽,通常我們返回頂部的按鈕的顯隱需要用到該方法,子類進行實現
*
* @param recyclerView
* @param dx
* @param dy
*/
protected abstract void initOnScrolled(RecyclerView recyclerView, int dx, int dy);
/**
* 初始化Adapter,子類進行實現
*
* @return adapter
*/
protected abstract T initAdapter();
/**
* 從伺服器介面載入資料,子類進行實現
*/
protected abstract void loadDataFromServer(boolean isShowProgress);
/**
* 下拉正在重新整理載入回撥方法
*
* @param refreshlayout
*/
protected abstract void onRefreshing(RefreshLayout refreshlayout);
/**
* 上拉正在載入更多回撥方法
*
* @param refreshlayout
*/
protected abstract void onLoadmoreing(RefreshLayout refreshlayout);
/**
* 初始化 頂部固定欄目View,需要子類重寫即可
*
* @param inflater
* @param topParent
* @return View
*/
protected View initTopFixedView(LayoutInflater inflater, LinearLayout topParent) {
return null;
}
/**
* 初始化 頂部可隨手勢上下移動顯隱的欄目View,需要子類重寫即可
*
* @param inflater
* @param topScrollParent
* @return View
*/
protected View initTopScrollView(LayoutInflater inflater, LinearLayout topScrollParent) {
return null;
}
/**
* 自定義RefreshLayout設定的方法,子類重新該方法設定即可
*
* @param smartRefreshLayout
*/
protected void initRefreshLayoutSetting(SmartRefreshLayout smartRefreshLayout) {
}
/**
* 初始化 指定重新整理的頭佈局樣式
* 子類需要定製重寫該方法
*/
protected RefreshHeader initRefreshHeader() {
return new ClassicsHeader(mContext).setSpinnerStyle(SpinnerStyle.Translate);//指定為經典Header,預設是 貝塞爾雷達Header
}
/**
* 初始化 指定重新整理的腳佈局樣式
* 子類需要定製重寫該方法
*/
protected RefreshFooter initRefreshFooter() {
return new ClassicsFooter(mContext).setSpinnerStyle(SpinnerStyle.Translate); //設定為平移模式
}
/**
* 初始化 SmartRefreshLayout
* 1、設定灰色背景
* 2、設定頭佈局、腳佈局
* 3、開啟滑動底部自動觸發載入更多功能
* 4、設定下拉重新整理、上拉載入更多的監聽回撥
*/
private void initSmartRefreshLayout() {
mRefreshLayout.setBackgroundResource(R.color.common_light_gray_color);
mRefreshLayout.setRefreshHeader(initRefreshHeader());
mRefreshLayout.setRefreshFooter(initRefreshFooter());
mRefreshLayout.setEnableAutoLoadmore(true);
mRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(final RefreshLayout refreshlayout) {
onRefreshing(refreshlayout);
}
});
mRefreshLayout.setOnLoadmoreListener(new OnLoadmoreListener() {
@Override
public void onLoadmore(final RefreshLayout refreshlayout) {
onLoadmoreing(refreshlayout);
}
});
}
/**
* 處理網路異常重新載入邏輯
*/
private void handleNotNetReload() {
mBtnNoNetReload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 判斷網路是否可用
if (NetworkUtils.isAvailable(mContext)) {
onNoNetReload();
return;
}
showToastError("網路異常");
}
});
}
/**
* 處理回頂部按鈕點選事件
*/
protected void handleGoTopClick() {
mImgTop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mRecylerView.scrollToPosition(0);
}
});
}
/**
* 設定預設單列顯示的RecylerView
*/
private void setDefaultRecylerView() {
mDefaultItemDecoration = initItemDecoration();
mDefaultLayoutManager = initLayoutManager();
mAdapter = initAdapter();
mRecylerView.setLayoutManager(mDefaultLayoutManager);
mRecylerView.addItemDecoration(mDefaultItemDecoration);
mRecylerView.setAdapter(mAdapter);
mRecylerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
initOnScrolled(recyclerView, dx, dy);
}
});
}
/**
* 顯示一鍵回頂部圖示
*/
protected void showGoTopIcon() {
if (mImgTop != null) {
mImgTop.setVisibility(View.VISIBLE);
}
}
/**
* 隱藏一鍵回頂部圖示
*/
protected void hideGoTopIcon() {
if (mImgTop != null) {
mImgTop.setVisibility(View.GONE);
}
}
/**
* 顯示空佈局
*/
protected void showEmptyView() {
mLlEmptyRoot.setVisibility(View.VISIBLE);
mRefreshLayout.setVisibility(View.GONE);
mNotNetRoot.setVisibility(View.GONE);
}
/**
* 顯示網路異常佈局
*/
protected void showNotNetView() {
mLlEmptyRoot.setVisibility(View.GONE);
mRefreshLayout.setVisibility(View.GONE);
mNotNetRoot.setVisibility(View.VISIBLE);
}
/**
* 顯示正常列表內容的View
*/
protected void showNormalContentView() {
mRefreshLayout.setVisibility(View.VISIBLE);
mLlEmptyRoot.setVisibility(View.GONE);
mNotNetRoot.setVisibility(View.GONE);
}
}
實踐:
1、先上一張效果圖
2、實踐程式碼:
請檢視專案中的以下幾個類
CommonProdListActivity
ProdListCategoryActivity
ProdListColumnActivity
ProdListCouponActivity
ProdListProDetReduceActivity
ProdListShopCarReduceActivity
小結:
該版本為初級版,程式碼比較簡單,未逐一分析。歡迎大家指正、批評。謝謝!
相關文章
- Flutter MVP 封裝FlutterMVP封裝
- MVP模式的經典封裝MVP模式封裝
- 基於javascript的拖拽類封裝^o^JavaScript封裝
- 【封裝小技巧】列表處理函式的封裝封裝函式
- Android之Activity基類封裝Android封裝
- js物件導向封裝級聯下拉選單列表JS物件封裝
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝(一)Android架構MVP模式RxJava封裝
- SmartRefreshLayout+BaseRecyclerviewAdapterHelper使用MVP方式實現下拉重新整理ViewAPTMVP
- MVP 在專案中的最佳實戰(封裝篇)MVP封裝
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝之多Url(七)Android架構MVP模式RxJava封裝
- php的curl封裝類PHP封裝
- 一、類的封裝性封裝
- 封裝xunsearch類封裝
- JS 封裝類JS封裝
- Vuex 的使用方式(初級版)Vue
- 封裝JDBC—非框架開發必備的封裝類封裝JDBC框架
- python 打飛機專案 ( 基類封裝 )Python封裝
- 十五、類與封裝的概念封裝
- http通訊類的封裝HTTP封裝
- 封裝Date工具類封裝
- JsonValue 封裝類JSON封裝
- 封裝Redis工具類封裝Redis
- MVP實戰心得---封裝Retrofit2.0+RxAndroid+RxBusMVP封裝Android
- SRAM中晶圓級晶片級封裝的需求晶片封裝
- 基於MongoDb官方C#驅動封裝MongoDbCsharpHelper類(CRUD類)MongoDBC#封裝CSharp
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝之檔案下載(二)Android架構MVP模式RxJava封裝
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝之檔案上傳(三)Android架構MVP模式RxJava封裝
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝之常見問題(四)Android架構MVP模式RxJava封裝
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝之斷點下載(五)Android架構MVP模式RxJava封裝斷點
- 15_類與封裝的概念封裝
- [ 造輪子 ] 手動封裝 AJAX (一) —— 基礎版封裝
- c#封裝DBHelper類C#封裝
- 4、類和物件—封裝物件封裝
- 自用驗證類封裝封裝
- 封裝獲取Class類封裝
- 【Android架構】基於MVP模式的Retrofit2+RXjava封裝之資料預處理(六)Android架構MVP模式RxJava封裝
- 基於AOP的MVP框架(一)GoMVP的使用MVP框架Go
- 【JavaScript框架封裝】實現一個類似於JQuery的動畫框架的封裝JavaScript框架封裝jQuery動畫