RecyclerView實現下拉重新整理與自動載入控制元件封裝
阿新 • • 發佈:2019-01-29
CommonAdapter.java
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<ViewHolder>
{
protected Context mContext;
protected int mLayoutId;
protected List<T> mDatas;
protected LayoutInflater mInflater;
protected OnItemClickListener mOnItemClickListener;
public CommonAdapter(Context context, int layoutId, List<T> datas)
{
mContext = context;
mInflater = LayoutInflater.from(context);
mLayoutId = layoutId;
mDatas = datas;
}
protected boolean isEnabled(int viewType) {
return true;
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType)
{
ViewHolder viewHolder = ViewHolder.createViewHolder(mContext, parent, mLayoutId);
setListener(parent, viewHolder, viewType);
return viewHolder;
}
protected void setListener(final ViewGroup parent, final ViewHolder viewHolder, int viewType) {
if (!isEnabled(viewType)) return;
viewHolder.getConvertView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
int position = viewHolder.getAdapterPosition();
mOnItemClickListener.onItemClick(v, viewHolder , position);
}
}
});
viewHolder.getConvertView().setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemClickListener != null) {
int position = viewHolder.getAdapterPosition();
return mOnItemClickListener.onItemLongClick(v, viewHolder, position);
}
return false;
}
});
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
convert(holder, mDatas.get(position),position);
}
protected abstract void convert(ViewHolder holder, T t,int position);
@Override
public int getItemCount()
{
return mDatas.size();
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
public interface OnItemClickListener {
void onItemClick(View view, RecyclerView.ViewHolder holder, int position);
boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position);
}
}
2.定義一個LoadMoreWrapper
LoadMoreWrapper.java
public class LoadMoreWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { public static final int ITEM_TYPE_LOAD_MORE = Integer.MAX_VALUE - 2; private RecyclerView.Adapter mInnerAdapter; private View mLoadMoreView; private int mLoadMoreLayoutId; private RelativeLayout mFooterView; private View mNodataView; public LoadMoreWrapper(RecyclerView.Adapter adapter) { mInnerAdapter = adapter; } private boolean hasLoadMore() { return mLoadMoreView != null || mLoadMoreLayoutId != 0; } private boolean isShowLoadMore(int position) { return hasLoadMore() && (position >= mInnerAdapter.getItemCount()); } @Override public int getItemViewType(int position) { if (isShowLoadMore(position)) { return ITEM_TYPE_LOAD_MORE; } return mInnerAdapter.getItemViewType(position); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == ITEM_TYPE_LOAD_MORE) { ViewHolder holder; if (mLoadMoreView != null) { mFooterView = (RelativeLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.myrecycle_footview, parent, false); mNodataView=LayoutInflater.from(parent.getContext()).inflate(R.layout.myrecycle_nodata_view, parent, false); mFooterView.addView(mLoadMoreView); mFooterView.addView(mNodataView); mNodataView.setVisibility(View.GONE); holder = ViewHolder.createViewHolder(parent.getContext(),mFooterView); } else { mFooterView = (RelativeLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.myrecycle_footview, parent, false); mNodataView=LayoutInflater.from(parent.getContext()).inflate(R.layout.myrecycle_nodata_view, parent, false); mLoadMoreView=LayoutInflater.from(parent.getContext()).inflate(R.layout.default_loading, parent, false); mFooterView.addView(mLoadMoreView); mFooterView.addView(mNodataView); mNodataView.setVisibility(View.GONE); holder = ViewHolder.createViewHolder(parent.getContext(),mFooterView); } return holder; } return mInnerAdapter.onCreateViewHolder(parent, viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (isShowLoadMore(position)) { if (mOnLoadMoreListener != null) { mOnLoadMoreListener.onLoadMoreRequested(); } return; } mInnerAdapter.onBindViewHolder(holder, position); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() { @Override public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) { if (isShowLoadMore(position)) { return layoutManager.getSpanCount(); } if (oldLookup != null) { return oldLookup.getSpanSize(position); } return 1; } }); } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { mInnerAdapter.onViewAttachedToWindow(holder); if (isShowLoadMore(holder.getLayoutPosition())) { setFullSpan(holder); } } private void setFullSpan(RecyclerView.ViewHolder holder) { ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp; p.setFullSpan(true); } } @Override public int getItemCount() { return mInnerAdapter.getItemCount() + (hasLoadMore() ? 1 : 0); } public interface OnLoadMoreListener { void onLoadMoreRequested(); } private OnLoadMoreListener mOnLoadMoreListener; public void setFootCanLoad(boolean footCanload) { if(hasLoadMore()) { if (footCanload) {//如果可以載入更多佈局 mNodataView.setVisibility(View.GONE); } else { mNodataView.setVisibility(View.VISIBLE); } } } public LoadMoreWrapper setOnLoadMoreListener(OnLoadMoreListener loadMoreListener) { if (loadMoreListener != null) { mOnLoadMoreListener = loadMoreListener; } return this; } public LoadMoreWrapper setLoadMoreView(View loadMoreView) { mLoadMoreView = loadMoreView; return this; } public LoadMoreWrapper setLoadMoreView(int layoutId) { mLoadMoreLayoutId = layoutId; return this; }
3.對recycleview 的封裝
public class MyRecycleView<T> extends LinearLayout { private static int VERTICAL = LinearLayout.VERTICAL; private static int HORIZONTAL = LinearLayout.HORIZONTAL; private RecyclerView recyclerView; private SwipeRefreshLayout swipeRfl; // private LinearLayoutManager layoutManager; private SwipeRefreshLayout.OnRefreshListener mRefreshListener; private CommonAdapter mAdapter; private RefreshLoadMoreListener mRefreshLoadMoreListner;//下拉和載入更多監聽 private ItemClickListener itemClickListener;//item點選監聽 private LinearLayout mExceptView; private LinearLayout mLoadingView; private boolean hasMore = false;//是否還有更多資料載入 private boolean canMore = true;//是否可以載入更多 private boolean isCanRefresh = true;//是否可以重新整理更多 private boolean isRefresh = false;//正在重新整理 private boolean isLoadMore = false;//正在載入更多 private LoadMoreWrapper mLoadMoreWrapper;//為了實現載入更多footview private static ImageView exceptIv;//異常圖片控制元件 private static TextView exceptTv;//異常內容文字控制元件 private static ProgressBar loadingIv;//正在載入圖片控制元件 private static TextView loadingTv;//正在載入文字控制元件 public MyRecycleView(Context context) { super(context); } public MyRecycleView(Context context, AttributeSet attrs) { super(context, attrs); LinearLayout rootLl = new LinearLayout(context); rootLl.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mLoadingView = initLoadingView(context); mLoadingView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mExceptView = initExceptionView(context); mExceptView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mExceptView.setVisibility(View.GONE); swipeRfl = new SwipeRefreshLayout(context); swipeRfl.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); swipeRfl.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light); FrameLayout bootLl = new FrameLayout(context); bootLl.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); recyclerView = new RecyclerView(context); recyclerView.setVerticalScrollBarEnabled(true); recyclerView.setHorizontalScrollBarEnabled(true); recyclerView.setLayoutParams(new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); bootLl.addView(mLoadingView); bootLl.addView(recyclerView); bootLl.addView(mExceptView); swipeRfl.addView(bootLl); rootLl.addView(swipeRfl); this.addView(rootLl); /** * 下拉至頂部重新整理監聽 */ mRefreshListener = new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { if (!isRefresh && !isLoadMore) { isRefresh = true; refresh(); } } }; swipeRfl.setOnRefreshListener(mRefreshListener); recyclerView.setHasFixedSize(true);//不是瀑布流這個將可以優化效能 } public MyRecycleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } /** * 錯誤提示介面初始化 * * @param context * @return */ private LinearLayout initExceptionView(Context context) { LinearLayout rootLl = new LinearLayout(context); rootLl.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); rootLl.setOrientation(LinearLayout.VERTICAL); rootLl.setGravity(Gravity.CENTER); exceptIv = new ImageView(context); exceptIv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 點選圖片重新整理 if (!isRefresh) { swipeRfl.setRefreshing(true); isRefresh = true; refresh(); } } }); //底部邊距 LinearLayout.LayoutParams ll = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); ll.setMargins(0, 0, 0, 32); exceptIv.setLayoutParams(ll); exceptTv = new TextView(context); exceptTv.setLayoutParams(ll); exceptTv.setTextSize(20.0f); exceptTv.setTextColor(Color.DKGRAY); //提示操作文字 TextView alertTv = new TextView(context); alertTv.setLayoutParams(ll); alertTv.setLayoutParams(ll); alertTv.setTextSize(18.0f); alertTv.setTextColor(Color.LTGRAY); alertTv.setText("點選圖片重新整理"); rootLl.addView(exceptIv); rootLl.addView(exceptTv); rootLl.addView(alertTv); return rootLl; } /** * 初始化正在載入頁面 * * @param context * @return */ private LinearLayout initLoadingView(Context context) { LinearLayout rootLl = new LinearLayout(context); rootLl.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); rootLl.setOrientation(LinearLayout.VERTICAL); rootLl.setGravity(Gravity.CENTER); loadingIv = new ProgressBar(context); //底部邊距 LinearLayout.LayoutParams ll = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); ll.setMargins(0, 0, 0, 32); loadingIv.setLayoutParams(ll); loadingTv = new TextView(context); loadingTv.setLayoutParams(ll); loadingTv.setTextSize(20.0f); loadingTv.setTextColor(Color.LTGRAY); rootLl.addView(loadingIv); rootLl.addView(loadingTv); return rootLl; } /** * drawableId 錯誤提示圖片 * exceptStr 錯誤提示語 */ public void customExceptView(int drawableId, String exceptStr) { recyclerView.setVisibility(View.INVISIBLE); mExceptView.setVisibility(View.VISIBLE); mLoadingView.setVisibility(View.INVISIBLE); exceptIv.setImageResource(drawableId); exceptTv.setText(exceptStr); swipeRfl.setEnabled(false);//出現錯誤之後,將設定無法下拉,運用點選圖片進行重新整理 } /** * drawableId 正在載入提示圖片 * exceptStr 正在載入提示語 */ public void customLoadView(String exceptStr) { recyclerView.setVisibility(View.INVISIBLE); mLoadingView.setVisibility(View.VISIBLE); mExceptView.setVisibility(View.INVISIBLE); loadingTv.setText(exceptStr); swipeRfl.setEnabled(false); } public void scrollToTop() { recyclerView.scrollToPosition(0); } public void setAdapter(CommonAdapter adapter) { if (adapter != null) { this.mAdapter = adapter; if (canMore) {//是否可以載入更多 mLoadMoreWrapper = new LoadMoreWrapper(mAdapter); mLoadMoreWrapper.setLoadMoreView(R.layout.default_loading); mLoadMoreWrapper.setOnLoadMoreListener(new LoadMoreWrapper.OnLoadMoreListener() { @Override public void onLoadMoreRequested() { /** * 無論水平還是垂直 */ if (hasMore && !isLoadMore && !isRefresh && canMore) { isLoadMore = true; loadMore(); } } }); recyclerView.setAdapter(mLoadMoreWrapper); } else { recyclerView.setAdapter(mAdapter); } mAdapter.setOnItemClickListener(new CommonAdapter.OnItemClickListener() { @Override public void onItemClick(View view, RecyclerView.ViewHolder holder, int position) { if (itemClickListener != null) itemClickListener.onClick(view, holder, position); } @Override public boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position) { if (itemClickListener != null) itemClickListener.onLongClick(view, holder, position); return true; } }); } } public void setHasMore(boolean enable) { this.hasMore = enable; mLoadMoreWrapper.setFootCanLoad(hasMore); } public boolean isHasMore() { return hasMore; } public boolean isCanMore() { return canMore; } public void setCanMore(boolean canMore) { this.canMore = canMore; } public void setPullRefreshEnable(boolean enable) { isCanRefresh = enable; swipeRfl.setEnabled(enable); } public boolean getPullRefreshEnable() { return swipeRfl.isEnabled(); } public void loadMore() { if (mRefreshLoadMoreListner != null && hasMore && canMore) { mRefreshLoadMoreListner.onLoadMore(); } } /** * 載入更多完畢,為防止頻繁網路請求,isLoadMore為false才可再次請求更多資料 */ public void setLoadMoreCompleted() { isLoadMore = false; } public void stopRefresh() { isRefresh = false; swipeRfl.setRefreshing(false); if (isCanRefresh) swipeRfl.setEnabled(true); } public void setRefreshLoadMoreListener(RefreshLoadMoreListener listener) { mRefreshLoadMoreListner = listener; } public void setOnItemClickListener(ItemClickListener listener) { itemClickListener = listener; } /** * 重新整理動作,用於請求網路資料 */ public void refresh() { swipeRfl.setRefreshing(true); //recyclerView.setVisibility(View.VISIBLE); mExceptView.setVisibility(View.INVISIBLE); if (mRefreshLoadMoreListner != null) { mRefreshLoadMoreListner.onRefresh(); } } public void notifyDataSetChanged() { //firstload佈局只能出現一次,所以這裡判斷如果顯示,就隱藏 if (mLoadingView.getVisibility() == View.VISIBLE) { recyclerView.setVisibility(View.VISIBLE); mExceptView.setVisibility(View.INVISIBLE); mLoadingView.setVisibility(View.INVISIBLE); } if (mLoadMoreWrapper != null) mLoadMoreWrapper.notifyDataSetChanged(); else mAdapter.notifyDataSetChanged(); } /** * 第一次自動載入,不與無資料用同樣佈局是因為,這裡要有動畫效果,所以單獨一個佈局 */ public void firstLoadingView(String exceptStr) { customLoadView(exceptStr); isRefresh = true; if (mRefreshLoadMoreListner != null) { mRefreshLoadMoreListner.onRefresh(); } } /** * 獲取重新整理資料以後的處理 * * @param actAllList * @param tmp */ public void setDateRefresh(ArrayList<T> actAllList, ArrayList<T> tmp) { actAllList.clear(); stopRefresh();//如果重新整理則停止重新整理 if (tmp.isEmpty()) { customExceptView(R.drawable.no_data, "這裡空空如也"); setHasMore(false); } else { recyclerView.setVisibility(View.VISIBLE); setHasMore(true); actAllList.addAll(tmp); } notifyDataSetChanged();//重新整理完畢 } /** * 獲取載入更多資料的處理 * * @param actAllList * @param tmpLoadmore */ public void setDateLoadMore(ArrayList<T> actAllList, ArrayList<T> tmpLoadmore) { if (tmpLoadmore.isEmpty()) { setHasMore(false);//如果沒有更多資料則設定不可載入更多 setLoadMoreCompleted();//載入完畢 stopRefresh();//如果重新整理則停止重新整理 return; } setHasMore(true); actAllList.addAll(tmpLoadmore); setLoadMoreCompleted();//載入完畢 notifyDataSetChanged();//載入更多完畢 stopRefresh();//如果重新整理則停止重新整理 } public void setLayoutManager(RecyclerView.LayoutManager layoutManager) { recyclerView.setLayoutManager(layoutManager); } /** * 下拉重新整理和自動載入監聽 */ public interface RefreshLoadMoreListener { public void onRefresh(); public void onLoadMore(); } public interface ItemClickListener { public void onClick(View view, RecyclerView.ViewHolder holder, int position); public void onLongClick(View view, RecyclerView.ViewHolder holder, int position); } }
6.具體用法
public class MainActivity extends BaseActivity implements MyRecycleView.RefreshLoadMoreListener { @Override protected int getContentView() { return R.layout.activity_main; } private MyRecycleView prrv; private int page = 1; private int num = 15;//測試資料的總數量 private final static int PAGESIZE = 10; private CommonAdapter<ActivityBean> mAdapter; /** * 全部活動資料來源 */ private ArrayList<ActivityBean> actAllList = new ArrayList<ActivityBean>(); private boolean isFirstIn = true;//是否第一次載入 @Override protected void afterView() { setTitle("下拉重新整理demo"); prrv = (MyRecycleView) findViewById(R.id.prrv);//繫結組合控制元件自定義的myrecycleview initAdapter();//初始化介面卡 prrv.setRefreshLoadMoreListener(this);//下拉上拉載入更多監聽 //prrv.setPullRefreshEnable(false);//禁用重新整理 //prrv.setCanMore(false);//禁用載入更多用在setAdapter()之前 //設定佈局管理 //recyclerView.setLayoutManager(); //recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); //LinearLayoutManager layoutManager = new LinearLayoutManager(this); StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL); //GridLayoutManager layoutManager= new GridLayoutManager(this, 2); prrv.setLayoutManager(layoutManager); prrv.setAdapter(mAdapter); //條目監聽 prrv.setOnItemClickListener(new MyRecycleView.ItemClickListener() { @Override public void onClick(View view, RecyclerView.ViewHolder holder, int position) { Toast.makeText(MainActivity.this, "click-pos = " + position, Toast.LENGTH_SHORT).show(); } @Override public void onLongClick(View view, RecyclerView.ViewHolder holder, int position) { Toast.makeText(MainActivity.this, "longclick-pos = " + position, Toast.LENGTH_SHORT).show(); } }); } /** * 初始化介面卡 */ private void initAdapter() { mAdapter = new CommonAdapter<ActivityBean>(this, R.layout.fragment_discover_cardview_item, actAllList) { @Override protected void convert(ViewHolder holder, ActivityBean a, int position) { holder.setText(R.id.activity_title, a.getActTitile()); /*holder.setText(R.id.activity_date, Utils.longtimeToDayDate(a .getStartDate()) + "-" + Utils.longtimeToDayDate(a.getEndDate()));*/ holder.setText(R.id.activity_date, a.getUrl()); } }; } /** * 首次進入重新整理 */ @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); // 第一次進入自動重新整理 if (isFirstIn) { prrv.firstLoadingView("資料載入中"); isFirstIn = false; } } /** * 載入分頁資料 */ public ArrayList<ActivityBean> loadNetDatas() { ArrayList<ActivityBean> tmp = new ArrayList<ActivityBean>(); int m = num < PAGESIZE ? num : PAGESIZE; for (int i = 0; i < m; i++) { ActivityBean ab = new ActivityBean(); ab.setActId(i * 10 + ""); if (i % 3 == 0) ab.setActTitile("下拉重新整理自動載入"); else { ab.setActTitile("下拉重新整理自動載入的recyclviewActivity"); } ab.setCollected(false); ab.setCollectNum(i); ab.setEndDate(1428881600); ab.setImgUrl(""); ab.setStartDate(1428681600); ab.setTop(false); if (i % 2 == 0) ab.setUrl("下拉重新整理自動載入"); else { ab.setUrl("下拉重新整理自動載入的recyclviewActivity"); } tmp.add(ab); num--; } return tmp; } @Override public void onRefresh() { num = 13; page = 1; mHandler.sendEmptyMessageDelayed(0, 2000); System.out.println("onRefresh"); } @Override public void onLoadMore() { // TODO Auto-generated method stub page++; mHandler.sendEmptyMessageDelayed(1, 2000); System.out.println("onLoadMore"); } private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case 0://處理重新整理的資料 ArrayList<ActivityBean> tmp = loadNetDatas(); prrv.setDateRefresh(actAllList, tmp); ToastUtil.ToastCenter(MainActivity.this, "重新整理完成"); break; case 1:// 處理載入更多的資料 ArrayList<ActivityBean> tmpLoadmore = loadNetDatas(); prrv.setDateLoadMore(actAllList, tmpLoadmore); break; } } }; @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_delete) { actAllList.clear(); prrv.notifyDataSetChanged(); page = 1; prrv.customExceptView(R.drawable.no_data, "這裡空空如也"); return true; } if (id == R.id.action_refreshable) { if (prrv.getPullRefreshEnable()) { prrv.setPullRefreshEnable(!prrv.getPullRefreshEnable()); } else { prrv.setPullRefreshEnable(!prrv.getPullRefreshEnable()); } return true; } if (id == R.id.action_loadmoreable) { if (prrv.isHasMore()) { prrv.setHasMore(!prrv.isHasMore()); } else { prrv.setHasMore(!prrv.isHasMore()); } return true; } if (id == R.id.action_stoprefresh) { prrv.stopRefresh(); return true; } if (id == R.id.action_scrollToTop) { prrv.scrollToTop(); return true; } return super.onOptionsItemSelected(item); } }