裝飾模式應用 為RecyclerView.Adapter新增上拉載入更多
阿新 • • 發佈:2018-11-28
這個包裝類主要有兩個關鍵點:
第一個是列表尾部新增一個條目,用於顯示各種載入的狀態,就是添加了一個特殊型別的holder。
第二個是監控列表滾動,滾動到我們新增的那個holder的時候,觸發我們需要的操作,比如修改holder裡的狀態文字等。
注意問題:
以前做過兩一個實現方案,主要的區別在第二點,方案沒有監控列表滾動,而是在新增的尾部的holder繫結操作的時候,進行回撥載入更多方案,然後在會掉中更新列表,原來類似。
原理介紹
1.新增一個新的型別的itemview用於顯示我們的載入狀態
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return R.layout.lib_base_list_item_loading;
} else {
return mAdapter.getItemViewType(position);
}
}
2.建立holder的時候需要做區分,繫結holder的時候去更新一下我們新增的holder上的文字狀態。
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == R.layout.lib_base_list_item_loading) {
View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new LoadingHolder(view, onLoadOrRetryListener) ;
} else {
return mAdapter.onCreateViewHolder(parent, viewType);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof LoadingHolder) {
((LoadingHolder) holder).bindHolder(mLoadState);
} else {
mAdapter.onBindViewHolder(holder, position);
}
}
3.設定一個監聽器,監聽RecyclerView.OnScrollListener的滾動事件,在這裡進行呼叫載入更多的方法回撥。
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (nextPageId == 0) {
return;
}
int itemCount = mLayoutManager.getItemCount();
int lastVisibleItemPosition = mLayoutManager.findLastVisibleItemPosition();
//最後顯示的view是不是我們列表的最後一個數據
if (lastVisibleItemPosition == itemCount - 1) {
//這個時候的重新整理狀態
int loadState = mAdapter.getLoadState();
//這裡限制哪幾種狀態不用呼叫onLoadMore(nextPageId); 方法
if (!isLoading && hasMore==LoadMoreAdapterWrapper.STATE_LOADING && loadState != LoadMoreAdapterWrapper.STATE_LOAD_FAILED
&& loadState != LoadMoreAdapterWrapper.STATE_LOAD) {
isLoading = true;
//通過hanlder呼叫方法,防止出現異常
new Handler().post(new Runnable() {
@Override
public void run() {
onLoadMore(nextPageId);
}
});
}
}
}
4.更新狀態的方法外部呼叫該方法來,改變最後一個view的狀態。下面是我使用到的狀態,可以根據自己的需求進行調成。
public void updatePageInfo(int nextPageId, int hasMore) {
this.nextPageId = nextPageId;
this.hasMore = hasMore;
this.isLoading = false;
switch (hasMore) {
case STATE_LOAD:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD);
break;
case STATE_LOADING:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOADING);
break;
case STATE_LOAD_FAILED:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_FAILED);
break;
case STATE_LOAD_HIDE:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_HIDE);
break;
case STATE_LOAD_HAVE_NO_DATA:
mAdapter.setLoadState(LoadMoreAdapterWrapper.STATE_LOAD_HAVE_NO_DATA);
break;
}
mAdapter.notifyDataSetChanged();
}
以上就是關鍵的實現點了。
補充一點,就是在佈局書網格的佈局時,需要對loading佈局進行處理,否則顯示會不正確,現象為loading佈局只能顯示在第一個單元格內
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
// 如果當前是footer的位置,那麼該item佔據2個單元格,正常情況下佔據1個單元格
return getItemViewType(position) == TYPE_FOOTER ? gridManager.getSpanCount() : 1;
}
});
}
}
使用步驟一:
你需要讓你的adapter繼承BaseRecyclerViewAdapter,主要是為了使用裡面的一些操作列表的方法。
使用步驟二:註釋的比較詳細
//要包裝的adapter
dateBaseAdapter = new DateBaseAdapter(this);
dateBaseAdapter.appendData(objects);
//佈局管理器
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//adapter包裝類初始化,將自己的adapter 穿入
LoadMoreAdapterWrapper stringWrapperAdapter = new LoadMoreAdapterWrapper<>(this, dateBaseAdapter);
//初始化我們自己的監聽方法
onLoadMoreListener = new LoadMoreAdapterWrapper.OnLoadMoreListener(linearLayoutManager, stringWrapperAdapter) {
@Override
public void onLoadMore(int nextPageId) {
LogUtils.d("--------" + page);
viewById.postDelayed(new Runnable() {
@Override
public void run() {
page++;
onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOAD_FAILED);
dateBaseAdapter.appendData(objects);
}
}, 1000);
}
};
stringWrapperAdapter.setOnLoadOrRetryListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewById.postDelayed(new Runnable() {
@Override
public void run() {
page++;
onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOAD);
dateBaseAdapter.appendData(objects);
}
}, 1000);
}
});
//第一次更新狀態
onLoadMoreListener.updatePageInfo(page, LoadMoreAdapterWrapper.STATE_LOADING);
//將監聽方法設定給recycler view
viewById.addOnScrollListener(onLoadMoreListener);
viewById.setLayoutManager(linearLayoutManager);
viewById.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.HORIZONTAL));
//將包裝類設定給recycler view
viewById.setAdapter(stringWrapperAdapter);
總結一下
雖然很多大神寫過這類文章,但是隻有自己動手實踐過才能更好的理解。