参考连接1:http://blog.csdn.net/bboyfeiyu/article/details/39935329
直奔主题,按照上面参考链接确实是满足需求,但RecyclerView作为一个比ListView更灵活的一个控件,完全取代ListView只是时间的问题。所以这篇博文是记录我自己的实现方法。
首先是RecyclerView增加上拉的时候 加载中的view动画,可以沿用上面参考链接的listview_footer.xml
在ListView中 我们可以用addHeaderView或者addFooterView添加头尾,但RecyclerView并没有这个功能,网上参考是改写RecyclerViewAdapter
1 public class RecyclerViewAdapter extends RecyclerView.Adapter<ViewHolder> { 2 3 private static final int TYPE_ITEM = 0; 4 private static final int TYPE_FOOTER = 1; 5 private Context mContext; 6 private List<listItemBean> mItemsList; 7 8 public RecyclerViewAdapter(Context context, List<listItemBean> itemsList) { 9 mContext=context; 10 mItemsList = itemsList; 11 } 12 13 @Override 14 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 15 if (viewType == TYPE_ITEM) { 16 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list_item,parent,false); 17 return new ItemViewHolder(view); 18 } else if (viewType == TYPE_FOOTER) { 19 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_footer,parent,false); 20 view.setVisibility(View.GONE); 21 return new FooterViewHolder(view); 22 } 23 return null; 24 } 25 26 27 @Override 28 public void onBindViewHolder(ViewHolder holder, int position) { 29 if (holder instanceof ItemViewHolder) { 30 listItemBean itemBean = mItemsList.get(position); 31 ((ItemViewHolder)holder).mDetailTextView.setText(itemBean.getDetailText()); 32 ((ItemViewHolder)holder).mMainTextView.setText(itemBean.getMainText()); 33 } 34 } 35 36 37 38 @Override 39 public int getItemCount() { 40 return mItemsList.size()+1; 41 //return mItemsList.size(); 42 } 43 44 @Override 45 public int getItemViewType(int position) { 46 if (position+1 == getItemCount()) { 47 return TYPE_FOOTER; 48 } else { 49 return TYPE_ITEM; 50 } 51 } 52 53 54 55 class ItemViewHolder extends RecyclerView.ViewHolder { 56 public final TextView mMainTextView; 57 public final TextView mDetailTextView; 58 public ItemViewHolder(View itemView) { 59 super(itemView); 60 mMainTextView = (TextView) itemView.findViewById(R.id.tv_main); 61 mDetailTextView= (TextView) itemView.findViewById(R.id.tv_detail); 62 } 63 } 64 65 class FooterViewHolder extends RecyclerView.ViewHolder{ 66 public final ProgressBar progressBar; 67 public final TextView loadingTips; 68 public FooterViewHolder(View view) { 69 super(view); 70 progressBar = (ProgressBar) view.findViewById(R.id.pull_to_refresh_load_progress); 71 loadingTips = (TextView) view.findViewById(R.id.pull_to_refresh_loading_text); 72 } 73 } 74 }
在返回FooterViewHolder的时候,有一句view.setVisibility(View.GONE); 稍候解释为什么怎么做。
在getItemCount()+1是为了FooterViewHolder预留一个view的位置,到此RecyclerView的改写基本完成,往下就是重点了
/////////////////////////////////////////喝口茶的分割线/////////////////////////////////////////
RefreshLayout中,首先肯定是要把getChildView的ListView改成RecyclerView,其中也要替换onScrolled的监听吧。这些就不详细论述了,直接上改变后的代码
private void getChildView() { int childs = getChildCount(); if (childs > 0) { View childView = getChildAt(0); if (childView instanceof RecyclerView) { mRecyclerView = (RecyclerView) childView; // 设置滚动监听器给RecyclerView, 使得滚动的情况下也可以自动加载 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // 滚动时到了最底部也可以加载更多 if (canLoad()) { loadData(); } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } }); Log.d(TAG, "### 找到RecyclerView"); } } }
第二个变化点,判断是否到了最底部函数isBottom;其中我们必须知道RecyclerView是有横 纵 瀑布等LayoutManager的,我们要恰当的分开处理。
/*判断是否到了最底部*/ private boolean isBottom() { RecyclerView.LayoutManager layoutManager = null; if (mRecyclerView != null) { layoutManager = mRecyclerView.getLayoutManager(); }else{ return false; } if(layoutManager instanceof LinearLayoutManager){ LinearLayoutManager lm = (LinearLayoutManager) mRecyclerView.getLayoutManager(); int position = lm.findLastVisibleItemPosition(); int itemCount = lm.getItemCount(); Log.d(TAG,"current position:"+position); Log.d(TAG,"itemCount:"+itemCount); if(position+1 == lm.getItemCount() && lm.findViewByPosition(position).getBottom() <= getHeight()){ Log.d(TAG, "RefreshLayout 滑动到底部了"); return true; } }else if(layoutManager instanceof StaggeredGridLayoutManager){ // http://www.imooc.com/qadetail/91200 Log.d(TAG, "layoutManager instanceof StaggeredGridLayoutManager not yet implemented"); Log.d(TAG, "RefreshLayout 滑动到底部了"); } return false; }
好了,离完工就差最后一步了,就是setLoading(true/false),我觉得参考链接的博主暴露这个接口真的设计得非常好,完全和原生的swipeRefreshLayout下拉刷新媲美。
也是废话不说,上更改后的代码
public void setLoading(boolean loading) { isLoading = loading; LinearLayoutManager lm = (LinearLayoutManager) mRecyclerView.getLayoutManager(); int position = lm.findLastVisibleItemPosition(); // int itemCount = mRecyclerView.getLayoutManager().getItemCount(); // int childCount = mRecyclerView.getLayoutManager().getChildCount(); // Log.d(TAG,"getChildCount:"+childCount); // Log.d(TAG,"getItemCount:"+itemCount); View lastView = lm.findViewByPosition(position); if (isLoading) { lastView.setVisibility(View.VISIBLE); } else { lastView.setVisibility(View.GONE); mDownY = 0; mLastY = 0; } }
来到这里大家应该都明白了之前,在onCreateViewHolder返回FooterViewHolder的时候,有一句view.setVisibility(View.GONE)吧,其实那个加载动画一直都在整个RecyclerView的底部,我只是在恰当的时间隐藏/展示它罢了。
但这里大家必须注意的就是,此时的RecyclerView的itemsize永远是比你实际数据多1的,这点请大家注意!!!重要的话只说一遍。
至于demo,基本上可参照原参考链接的,这里也分享一下近日自己做的一个记账app,简单粗暴。
https://github.com/MrZhaozhirong/MyBill