-
Notifications
You must be signed in to change notification settings - Fork 140
Home
ByRecyclerView是一个用来处理App中列表展示的框架。它最大的优点在于,RecyclerView
和Adatper
两者可以分开使用、自带下拉刷新也可使用SwipeRefreshLayout、不足一屏上拉才加载更多。
- 1.支持 下拉刷新、加载更多
- 2.可随意切换 自带下拉刷新布局 / SwipeRefreshLayout
- 3.加载更多机制:手动上拉才执行加载更多
- 4.可设置自定义 下拉刷新布局 和 加载更多布局
- 5.添加/移除 HeaderView、FooterView
- 6.设置各种状态布局 EmptyView / LoadingView / ErrorView
- 7.添加item的点击/长按事件(防止重复点击)
- 8.优化过的BaseAdapter (RV/LV),减少大量代码
- 9.Adapter结合DataBinding使用 (RV/LV)
- 10.可添加万能分隔线(线性/宫格/瀑布流)
- 11.可设置粘性header,StickyView
- 12.可配置Skeleton骨架图
- 13.item 局部刷新
先在 build.gradle 的 repositories 添加
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
然后在dependencies添加
dependencies {
implementation 'com.github.youlookwhat:ByRecyclerView:1.1.6'
implementation "com.github.youlookwhat:ByRecyclerView:1.0.18-support" // support版本已不再支持
}
- 加入布局
<me.jingbin.library.ByRecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layoutManager="LinearLayoutManager"
tools:listitem="@layout/item_home" />
- 使用BaseRecyclerAdapter
public class OneTypeAdapter extends BaseRecyclerAdapter<String> {
public OneTypeAdapter(List<String> data) {
super(R.layout.item_main, data);
}
@Override
protected void bindView(BaseByViewHolder<String> holder, String bean, int position) {
holder.setText(R.id.view_bottom, bean);
}
}
mAdapter.setNewData(list); // 设置第一页数据
- 加载更多监听
mRecyclerView.setOnLoadMoreListener(new ByRecyclerView.OnLoadMoreListener() {
@Override
public void onLoadMore() {
mAdapter.addData(list); // 设置及刷新数据
mRecyclerView.loadMoreComplete(); // 加载更多完成
mRecyclerView.loadMoreEnd(); // 没有更多内容了
mRecyclerView.loadMoreFail(); // 加载更多失败
}
});
集合下拉刷新、加载更多、添加/移除HeaderView或FooterView、设置EmptyView等,也可以使用自己定义的BaseAdapter
默认关闭,设置监听后标明启用。也可手动再设置关闭。
mRecyclerView.setOnRefreshListener(new ByRecyclerView.OnRefreshListener() {
@Override
public void onRefresh() {
mAdapter.setNewData(list); // 设置及刷新数据
}
});
// 需要在设置监听后设置,设置监听会开启自动刷新
mRecyclerView.setRefreshEnabled(false);
mRecyclerView.setRefreshing(true); // 手动启动刷新
mRecyclerView.setRefreshing(false); // 取消刷新重置参数,包括加载更多的参数
刷新机制:不满一屏上拉加载更多,满一屏后触底加载更多。 设置监听即表示开启加载更多。不设置默认不开启。
// 想要使用加载更多,必须设置监听或将加载更多开关打开。
// 只打开开关不设置加载更多监听,多出现在只想在列表最后设置`没有更多数据了`的布局。
mRecyclerView.setLoadMoreEnabled(true);
mRecyclerView.setOnLoadMoreListener(new ByRecyclerView.OnLoadMoreListener() {
@Override
public void onLoadMore() {
mAdapter.addData(list); // 设置及刷新数据(对应adapter方法)
mRecyclerView.loadMoreComplete(); // 加载更多完成
mRecyclerView.loadMoreEnd(); // 没有更多内容了
mRecyclerView.loadMoreFail(); // 加载更多失败(点击或再次上拉都会再次调用加载更多接口)
}
}, delayMillis);// delayMillis: 延迟多少毫秒调用接口
mRecyclerView.setOnItemClickListener(new ByRecyclerView.OnItemClickListener() {
@Override
public void onClick(View v, int position) {
DataItemBean itemData = mAdapter.getItemData(position);// 通过adapter获取对应position的数据
}
});
// 防止重复点击
mRecyclerView.setOnItemClickListener(new OnItemFilterClickListener() {
@Override
protected void onSingleClick(View v, int position) {
}
});
mRecyclerView.setOnItemLongClickListener(new ByRecyclerView.OnItemLongClickListener() {
@Override
public boolean onLongClick(View v, int position) {
return false;
}
});
每一个headerView都将对应一个viewType,这将可以通过headerView实现锚点的效果。可传入View或对应布局layout。注意:不可频繁的add和remove
// add
recyclerView.addHeaderView(getView() / layoutId);
// remove
recyclerView.removeHeaderView(getView() / layoutId));
// removeAll
recyclerView.removeAllHeaderView();
// 不显示headerView,调用后需要刷新adapter
recyclerView.setHeaderViewEnabled(false);
// 获取view对应databinding,注意:recyclerView.getParent()
LayoutHeaderViewBinding headerBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.layout_header_view, (ViewGroup) binding.recyclerView.getParent(), false);
多个footerView只是单一的viewType;可传入View或对应布局layout。
// add
recyclerView.addFooterView(getView() / layoutId));
// remove
recyclerView.removeFooterView(getView() / layoutId));
// removeAll
recyclerView.removeAllFooterView();
// 不显示footerView,调用后需要刷新adapter
recyclerView.setFootViewEnabled(false);
loadingView / emptyView / errorView 只会存在一个,所以调用这个方法即可
recyclerView.setStateView(getView() / layoutId);
// 不显示stateView,调用后需要刷新adapter
recyclerView.setStateViewEnabled(false);
// 不满一屏无法上拉加载更多
recyclerView.setNotFullScreenNoLoadMore();
给加载更多底部增加一个高度,单位dp。这样的设计主要是为了底部如果有透明栏,加载更多布局不会被覆盖。
// 为了底部透明显示
recyclerView.setLoadingMoreBottomHeight(50);
使用者可以根据项目需求自定义布局,需要继承BaseRefreshHeader
// 设置下拉刷新布局
recyclerView.setRefreshHeaderView(new NeteaseRefreshHeaderView(this));
仿网易云音乐Ios版下拉刷新布局示例:NeteaseRefreshHeaderView
自定义加载中,无内容,失败的布局,继承 BaseLoadMore
// 设置加载更多布局
recyclerView.setLoadingMoreView(new NeteaseLoadMoreView(this));
仿网易云音乐Ios版加载更多布局示例:NeteaseLoadMoreView
// 首先需要在ViewHolder里添加点击事件
holder.addOnClickListener(R.id.tv_text);
// 然后给recyclerView设置子view点击监听
recyclerView.setOnItemChildClickListener(new ByRecyclerView.OnItemChildClickListener() {
@Override
public void onItemChildClick(View view, int position) {
switch (view.getId()) {
case R.id.tv_text:
break;
default:
break;
}
}
});
// 设置防重复的点击事件
recyclerView.setOnItemChildClickListener(new OnItemChildFilterClickListener() {
@Override
public void onSingleClick(View view, int position) {
}
});
// 首先需要在ViewHolder里添加从长按事件
holder.addOnLongClickListener(R.id.tv_text);
// 然后给recyclerView设置长按监听
recyclerView.setOnItemChildLongClickListener(new ByRecyclerView.OnItemChildLongClickListener() {
@Override
public void onItemChildLongClick(View view, int position) {
switch (view.getId()) {
case R.id.tv_text:
break;
default:
break;
}
}
});
// 设置要局部刷新的position及payload
adapter.refreshNotifyItemChanged(position, PayloadAdapter.PAYLOAD_COLLECT);
// adapter里额外再继承 bindViewPayloads 方法
@Override
protected void bindViewPayloads(@NonNull BaseBindingHolder holder, @NonNull DataItemBean bean, @NonNull ItemPayloadBinding binding, int position, @NonNull List<Object> payloads) {
for (Object p : payloads) {
int code = (int) p;
switch (code) {
case PAYLOAD_ZAN:
binding.tvZan.setText(bean.getIsZan() == 1 ? "已赞" : "点赞");
break;
case PAYLOAD_COLLECT:
binding.tvCollect.setText(bean.getIsCollect() == 1 ? "已收藏" : "收藏");
break;
default:
break;
}
}
}
目前有三种Adapter,两种ViewHolder:
- BaseByRecyclerViewAdapter(所有adapter超类)
- BaseRecyclerAdapter (单类型极简adapter)
- BaseBindingAdapter (使用了databinding的单类型极简adapter)
- BaseByViewHolder (所有ViewHolder超类)
- BaseBindingHolder (使用了databinding的ViewHolder)
简单点说:
- 多类型展示使用
BaseByRecyclerViewAdapter
,其中使用的ViewHolder可以是BaseByViewHolder
或BaseBindingHolder
- 单类型展示使用
BaseRecyclerAdapter
或BaseBindingAdapter
,区别是后者使用了databinding
注意:
- 因为databinding是在编译时生成对应xml文件的类,所以需要使用者拷贝项目中的binding文件夹里的类。
public class OneTypeAdapter extends BaseRecyclerAdapter<DataItemBean> {
public OneTypeAdapter(List<DataItemBean> data) {
super(R.layout.item_main, data);
}
@Override
protected void bindView(BaseByViewHolder<DataItemBean> holder, DataItemBean bean, int position) {
holder.setText(R.id.tv_text, bean.getTitle())
.addOnClickListener(R.id.tv_text) // 子view点击事件
.addOnLongClickListener(R.id.tv_text); // 子view长按事件
}
}
public class DataAdapter extends BaseBindingAdapter<DataItemBean, ItemHomeBinding> {
public DataAdapter() {
super(R.layout.item_home);
}
public DataAdapter(List<DataItemBean> data) {
super(R.layout.item_home, data);
}
@Override
protected void bindView(BaseBindingHolder holder, ItemHomeBinding binding, DataItemBean bean, int position) {
binding.tvText.setText(bean.getTitle() + ": " + position);
}
}
使用 BaseByRecyclerViewAdapter 结合 BaseBindingHolder 或 BaseByViewHolder
public class MultiAdapter extends BaseByRecyclerViewAdapter<DataItemBean, BaseByViewHolder<DataItemBean>> {
public MultiAdapter(List<DataItemBean> data) {
super(data);
}
@Override
public int getItemViewType(int position) {
DataItemBean itemData = getItemData(position);
if ("title".equals(itemData.getType())) {
return 1;
} else {
return 2;
}
}
@NonNull
@Override
public BaseByViewHolder<DataItemBean> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (1 == viewType) {
return new TitleHolder(parent, R.layout.item_multi_title);
} else {
return new ViewHolder(parent, R.layout.item_home);
}
}
private class TitleHolder extends BaseByViewHolder<DataItemBean> {
TitleHolder(ViewGroup viewGroup, int layoutId) {
super(viewGroup, layoutId);
}
@Override
protected void onBaseBindView(BaseByViewHolder<DataItemBean> holder, DataItemBean bean, int position) {
holder.setText(R.id.tv_title, bean.getDes());
}
}
private class ViewHolder extends BaseBindingHolder<DataItemBean, ItemHomeBinding> {
ViewHolder(ViewGroup viewGroup, int layoutId) {
super(viewGroup, layoutId);
}
@Override
protected void onBindingView(BaseBindingHolder holder, DataItemBean bean, int position) {
binding.tvText.setText(bean.getDes());
}
}
}
可设置
drawable
,也可以直接设置颜色,高度,左右间距。并可以设置头部和尾部不显示item的个数,例如添加了header,不想在此header下添加分割线,则可以通过setHeaderNoShowDivider()
方法处理。具体实现类:SpacesItemDecoration。
// 第二个参数表示 是纵向还是横向
SpacesItemDecoration itemDecoration = new SpacesItemDecoration(this, SpacesItemDecoration.VERTICAL)
.setNoShowDivider(1, 1) // 第一个参数:头部不显示分割线的个数,第二个参数:尾部不显示分割线的个数,默认为1
.setDrawable(R.drawable.shape_line);// 设置drawable文件
recyclerView.addItemDecoration(itemDecoration);
也可设置横向或纵向
SpacesItemDecoration itemDecoration = new SpacesItemDecoration(this, SpacesItemDecoration.VERTICAL)
.setNoShowDivider(1, 1)
// 颜色,分割线间距,左边距(单位dp),右边距(单位dp)
.setParam(R.color.colorBlue, 10, 70, 70);
recyclerView.addItemDecoration(itemDecoration);
可以设置两种风格的分割线,1.四周没有间距,2.四周有间距。也可以设置头部和尾部不显示item的个数,具体实现类:GridSpaceItemDecoration
GridSpaceItemDecoration itemDecoration = new GridSpaceItemDecoration(10, true)
.setNoShowSpace(1, 1);
recyclerView.addItemDecoration(itemDecoration);
/**
* @param spacing item 间距
* @param includeEdge item 距屏幕周围是否也有间距
*/
public GridSpaceItemDecoration(int spacing, boolean includeEdge)
/**
* 设置从哪个位置 结束设置间距
*
* @param startFromSize 一般为HeaderView的个数 + 刷新布局(不一定设置)
* @param endFromSize 默认为1,一般为FooterView的个数 + 加载更多布局(不一定设置)
*/
public GridSpaceItemDecoration setNoShowSpace(int startFromSize, int endFromSize)
1、使用StickyLinearLayoutManager,传入adapter
StickyLinearLayoutManager layoutManager = new StickyLinearLayoutManager(getContext(), mAdapter);
2、在adapter里,将悬浮的item的ItemViewType设置为StickyHeaderHandler.TYPE_STICKY_VIEW
@Override
public int getItemViewType(int position) {
if ("title".equals(getItemData(position).getType())) {
return StickyHeaderHandler.TYPE_STICKY_VIEW;
} else {
return 2;
}
}
也可以使用StickyGridLayoutManager,只需将最后一个参数传入 adapter 即可
注意:使用置顶item时,不能使用自带的下拉刷新。
骨架图处理,在设置完 ByRV 的一切配置后执行,可设置 list、grid、View、HeaderView 具体请见项目示例代码
通过额外setAdapter实现 【在之前 不能 setAdapter()】 示例代码:
// 显示
skeletonScreen = BySkeleton
.bindItem(binding.recyclerView)
.adapter(mAdapter)// 必须设置adapter,且在此之前不要设置adapter
.shimmer(false)// 是否有动画
.load(R.layout.layout_by_default_item_skeleton)// item骨架图
.angle(30)// 微光角度
.frozen(false) // 是否不可滑动
.color(R.color.colorWhite)// 动画的颜色
.duration(1500)// 微光一次显示时间
.count(10)// item个数
.show();
// 隐藏
skeletonScreen.hide();
通过setStateView实现 【在之前 需要 setAdapter()】 示例代码:
// 显示
skeletonScreen = BySkeleton
.bindView(binding.recyclerView)
.load(R.layout.layout_skeleton_view)// view骨架图
.shimmer(true)// 是否有动画
.angle(20)// 微光角度
.color(R.color.colorWhite)// 动画的颜色
.duration(1500)// 微光一次显示时间
.show();
// 隐藏
skeletonScreen.hide();
1 引入及极速设置
- 2.1 使用自带下拉刷新
- 2.2 使用加载更多
- 2.3 添加item点击事件
- 2.4 添加item长按事件
- 2.5 addHeaderView
- 2.6 addFooterView
- 2.7 setStateView
- 2.8 不满一屏不加载
- 2.9 加载更多底部间距
- 2.10 自定义下拉刷新
- 2.11 自定义加载更多
- 2.12 子View点击事件
- 2.13 子View长按事件
- 2.14 item 局部刷新
3 Adapter
- 3.1 单类型列表
- 3.2 单类型列表(databinding)
- 3.3 多类型列表实现