*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
很想给大家分享这个开源项目,但是由于工作的关系,没有抽出空,但还是趁着工作间隙写下了这篇博客。
SuperRecyclerView是支持addHeaderView、 addFooterView、下拉刷新、分页加载数据的RecyclerView。
它对 RecyclerView 控件进行了拓展,给RecyclerView增加HeaderView、FooterView,并且不需要对你的Adapter做任何修改。
项目地址:https://github.com/jdsjlzx/SuperRecyclerView
如果我比别人看得远些,那是因为我站在巨人们的肩上。 (牛顿)
本开源控件是基于 HeaderAndFooterRecyclerView 开源项目而来,在原基础上进行了扩充。在此感谢cundong作者(github地址:https://github.com/cundong)。
mDataAdapter = new DataAdapter(this);
mDataAdapter.setData(dataList);
mHeaderAndFooterRecyclerViewAdapter = new HeaderAndFooterRecyclerViewAdapter(this, mDataAdapter);
mRecyclerView.setAdapter(mHeaderAndFooterRecyclerViewAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//add a HeaderView
RecyclerViewUtils.setHeaderView(mRecyclerView, new SampleHeader(this));
//add a FooterView
RecyclerViewUtils.setFooterView(mRecyclerView, new SampleFooter(this));
mRecyclerView.addOnScrollListener(mOnScrollListener);
RecyclerOnScrollListener mOnScrollListener = new RecyclerOnScrollListener() {
@Override
public void onBottom() {
LoadingFooter.State state = RecyclerViewStateUtils.getFooterViewState(mRecyclerView);
if(state == LoadingFooter.State.Loading) {
Log.d(TAG, "the state is Loading, just wait..");
return;
}
if (mCurrentCounter < TOTAL_COUNTER) {
// loading more
RecyclerViewStateUtils.setFooterViewState(EndlessLinearLayoutActivity.this, mRecyclerView, REQUEST_COUNT, LoadingFooter.State.Loading, null);
requestData();
} else {
//the end
RecyclerViewStateUtils.setFooterViewState(EndlessLinearLayoutActivity.this, mRecyclerView, REQUEST_COUNT, LoadingFooter.State.TheEnd, null);
}
}
};
RecyclerOnScrollListener实现了onScrollUp()、onScrollDown()、onBottom()、onScrolled四个事件,如下所示:
public abstract void onScrollUp();//scroll down to up
public abstract void onScrollDown();//scroll from up to down
public abstract void onBottom();//load next page
public abstract void onScrolled(int distanceX, int distanceY);// moving state,you can get the move distance
从上面的RecyclerOnScrollListener类的介绍中就可以看出,实现加载更多只要在onBottom()接口中处理即可。
为了达到和Listview的下拉刷新效果,本项目没有借助SwipeRefreshLayout控件,而是在自定义RecyclerView头部实现的刷新效果。
这里的下拉刷新效果借鉴了开源库:AVLoadingIndicatorView
设置加载样式:
mRecyclerView.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader);
mRecyclerView.setArrowImageView(R.drawable.iconfont_downgrey);
AVLoadingIndicatorView库有多少效果,SuperRecyclerView就支持多少下拉刷新效果,当然你也可以自定义下拉效果。
效果图:
下拉刷新逻辑处理:
mRecyclerView.setLoadingListener(new CustRecyclerView.LoadingListener() {
@Override
public void onRefresh() {
requestData();
}
});
这里自定义了一个接口LoadingListener,如下所示:
public interface LoadingListener {
void onRefresh();
}
下拉刷新只要在onRefresh()方法中处理即可。
加载数据时如果网络异常或者断网,SuperRecyclerView为你提供了重新加载的机制。
效果图:
网络异常出错代码处理如下:
RecyclerViewStateUtils.setFooterViewState(getActivity(), mRecyclerView, getPageSize(), LoadingFooter.State.NetWorkError, mFooterClick);
private View.OnClickListener mFooterClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
RecyclerViewStateUtils.setFooterViewState(getActivity(), mRecyclerView, getPageSize(), LoadingFooter.State.Loading, null);
requestData();
}
};
上面的mFooterClick就是我们点击底部的Footer时的逻辑处理事件,很显然我们还是在这里做重新请求数据操作。
在Hongyang前辈的博客中有下描述:
Click and LongClick
不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。
不过我们也可以自己去添加,只是会多了些代码而已。
实现的方式比较多,你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势, 当然你也可以通过adapter中自己去提供回调,这里我们选择后者,前者的方式,大家有兴趣自己去实现。
出自:http://blog.csdn.net/lmj623565791/article/details/45059587
Hongyang大神选择了后者,SuperRecyclerView选择了前者。
先看下怎么使用:
mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, mRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
ItemModel item = mDataAdapter.getDataList().get(position);
Toast.makeText(EndlessLinearLayoutActivity.this, item.title, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, final int position) {
ItemModel item = mDataAdapter.getDataList().get(position);
Toast.makeText(EndlessLinearLayoutActivity.this, "onItemLongClick - " + item.title, Toast.LENGTH_SHORT).show();
}
}));
原理就是监听RecyclerView.OnItemTouchListener事件,判断手势区别是点击还是长按。由于代码过多就不贴出来了。
如果item里面有按钮也有单独的点击事件,利用上面的方式就好出现冲突,此时不要再使用mRecyclerView.addOnItemTouchListener接口,这里给出另一种实现方法。
代码如下:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ProductViewHolder viewHolder = (ProductViewHolder) holder;
viewHolder.title.setText("产品");
viewHolder.buyBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// button click event
}
});
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// item click event
}
});
}
viewHolder.itemView是RecyclerView中本身就具有的,不用额外定义。
源码如下:
public static abstract class ViewHolder {
public final View itemView;
int mPosition = NO_POSITION;
int mOldPosition = NO_POSITION;
long mItemId = NO_ID;
int mItemViewType = INVALID_TYPE;
int mPreLayoutPosition = NO_POSITION;
介绍完了SuperRecyclerView,似乎还少些什么,对了,那就是adapter了。
为了方便大家使用,分享个封装过的adapter。
public class ListBaseAdapter<T extends Entity> extends RecyclerView.Adapter {
protected Context mContext;
protected int mScreenWidth;
public void setScreenWidth(int width) {
mScreenWidth = width;
}
protected ArrayList<T> mDataList = new ArrayList<>();
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return mDataList.size();
}
public List<T> getDataList() {
return mDataList;
}
public void setDataList(Collection<T> list) {
this.mDataList.clear();
this.mDataList.addAll(list);
notifyDataSetChanged();
}
public void addAll(Collection<T> list) {
int lastIndex = this.mDataList.size();
if (this.mDataList.addAll(list)) {
notifyItemRangeInserted(lastIndex, list.size());
}
}
public void clear() {
mDataList.clear();
notifyDataSetChanged();
}
}
ListBaseAdapter使用了泛型,简单方便,消除了强制类型转换。
使用如下:
private class DataAdapter extends ListBaseAdapter<ItemModel>{
private LayoutInflater mLayoutInflater;
public DataAdapter(Context context) {
mLayoutInflater = LayoutInflater.from(context);
mContext = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(mLayoutInflater.inflate(R.layout.sample_item_text, parent, false));
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ItemModel item = mDataList.get(position);
ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.textView.setText(item.title);
}
private class ViewHolder extends RecyclerView.ViewHolder {
private TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.info_text);
}
}
}
ListBaseAdapter虽然功能不强大,但是使用很方便。
SuperRecyclerView使用方便简单,无论你添加多少Header和Footer,你都不用担心position的问题,除了方便还是方便。
最后再介绍下项目地址:https://github.com/jdsjlzx/SuperRecyclerView
如果大家使用过程中有任何问题,请留言或者QQ反馈,我会及时修正。