Skip to content
景彬 edited this page Dec 29, 2019 · 39 revisions

概述

ByRecyclerView是一个用来处理App中列表展示的框架。它结合了优化过的RecyclerView多种BaseRecyclerViewAdapter,最大的优点在于两者可以分开使用可自定义刷新头部可自定义加载更多不足第一屏上拉才加载更多可结合SwipeRefreshLayout或其他刷新控件等。

特性

  • 1.支持 下拉刷新、加载更多
  • 2.可随意切换 自带下拉刷新布局 / SwipeRefreshLayout
  • 3.加载更多机制:手动上拉才执行加载更多
  • 4.可设置自定义 下拉刷新布局 和 加载更多布局
  • 5.添加/移除 HeaderView、FooterView
  • 6.设置各种状态布局 EmptyView / LoadingView / ErrorView
  • 7.添加item的点击/长按事件
  • 8.优化过的BaseAdapter (RecyclerView / ListView),减少大量代码
  • 9.Adapter结合DataBinding使用 (RecyclerView / ListView)
  • 10.可添加万能分隔线(LinearLayout / GridLayout / StaggeredGridLayout)
  • 11.默认使用AndoridX,且支持Support

主要类介绍

ByRecyclerView

  • addHeaderView/addFooterView
  • setEmptyView
  • 设置下拉刷新
  • 设置加载更多

Adapter

  • BaseByRecyclerViewAdapter - 万能适配器
  • BaseRecyclerAdapter - 单个item类型适配器
  • BaseBindingAdapter - 集合DataBinding的单个item类型适配器

1 引入及极速设置

1.1 引入

先在 build.gradle 的 repositories 添加

allprojects {
	repositories {
		...
		maven { url "https://jitpack.io" }
	}
}

然后在dependencies添加

dependencies {
	implementation 'com.github.youlookwhat:ByRecyclerView:1.0.9'         // 默认AndroidX版本
	implementation "com.github.youlookwhat:ByRecyclerView:1.0.9-support" // support版本引入
}

1.2 极速设置

  • 加入布局
<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();      // 加载更多失败
    }
});

2 ByRecyclerView

集合下拉刷新、加载更多、添加/移除HeaderView或FooterView、设置EmptyView等,也可以使用自己定义的BaseAdapter

2.1 使用自带下拉刷新

默认关闭,设置监听后标明启用。也可手动再设置关闭。

mRecyclerView.setOnRefreshListener(new ByRecyclerView.OnRefreshListener() {
    @Override
    public void onRefresh() {
        mAdapter.setNewData(list);  // 设置及刷新数据
    }
});

// 需要在设置监听后设置,设置监听会开启自动刷新
mRecyclerView.setRefreshEnabled(false); 

mRecyclerView.setRefreshing(true);  // 手动启动刷新
mRecyclerView.setRefreshing(false); // 取消刷新重置参数,包括加载更多的参数

2.2 使用加载更多

刷新机制:不满一屏上拉加载更多,满一屏后触底加载更多。 设置监听即表示开启加载更多。不设置默认不开启。

// 想要使用加载更多,必须设置监听或将加载更多开关打开。
// 只打开开关不设置加载更多监听,多出现在只想在列表最后设置`没有更多数据了`的布局。
mRecyclerView.setLoadMoreEnabled(true);

mRecyclerView.setOnLoadMoreListener(new ByRecyclerView.OnLoadMoreListener() {
    @Override
    public void onLoadMore() {
         mAdapter.addData(list);            // 设置及刷新数据(对应adapter方法)
         mRecyclerView.loadMoreComplete();  // 加载更多完成 
         mRecyclerView.loadMoreEnd();       // 没有更多内容了
         mRecyclerView.loadMoreFail();      // 加载更多失败(点击或再次上拉都会再次调用加载更多接口)
    }
}, delayMillis);// delayMillis: 延迟多少毫秒调用接口

2.3 添加item点击事件

mRecyclerView.setOnItemClickListener(new ByRecyclerView.OnItemClickListener() {
    @Override
    public void onClick(View v, int position) {
        DataItemBean itemData = mAdapter.getItemData(position);// 通过adapter获取对应position的数据
    }
});

2.4 添加item长按事件

mRecyclerView.setOnItemLongClickListener(new ByRecyclerView.OnItemLongClickListener() {
    @Override
    public boolean onLongClick(View v, int position) {
        return false;
    }
});

2.5 addHeaderView(多type)

每一个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);

2.6 addFooterView

多个footerView只是单一的viewType;可传入View或对应布局layout。

// add
recyclerView.addFooterView(getView() / layoutId));
// remove
recyclerView.removeFooterView(getView() / layoutId));
// removeAll
recyclerView.removeAllFooterView();

// 不显示footerView,调用后需要刷新adapter
recyclerView.setFootViewEnabled(false);

2.7 setStateView(空布局、加载中布局、错误布局)

loadingView / emptyView / errorView 只会存在一个,所以调用这个方法即可

recyclerView.setStateView(getView() / layoutId);

// 不显示stateView,调用后需要刷新adapter
recyclerView.setStateViewEnabled(false);

2.8 设置不满一屏不加载

// 不满一屏无法上拉加载更多
recyclerView.setNotFullScreenNoLoadMore();

2.9 设置加载更多布局底部间距

给加载更多底部增加一个高度,单位dp。这样的设计主要是为了底部如果有透明栏,加载更多布局不会被覆盖。

// 为了底部透明显示
recyclerView.setLoadingMoreBottomHeight(50);

2.10 自定义下拉刷新布局

使用者可以根据项目需求自定义布局,需要继承BaseRefreshHeader

// 设置下拉刷新布局
recyclerView.setRefreshHeaderView(new NeteaseRefreshHeaderView(this));

仿网易云音乐Ios版下拉刷新布局示例:NeteaseRefreshHeaderView

2.11 自定义加载更多布局

自定义加载中,无内容,失败的布局,继承 BaseLoadMore

// 设置加载更多布局
recyclerView.setLoadingMoreView(new NeteaseLoadMoreView(this));

仿网易云音乐Ios版加载更多布局示例:NeteaseLoadMoreView

2.12 添加子View的点击事件

// 首先需要在ViewHolder里添加点击事件
holder.addOnClickListener(R.id.tv_text);

// 然后给recyclerView设置点击监听
recyclerView.setOnItemChildClickListener(new ByRecyclerView.OnItemChildClickListener() {
    @Override
    public void onItemChildClick(View view, int position) {
        switch (view.getId()) {
            case R.id.tv_text:
                break;
            default:
                break;
        }
    }
});

2.13 添加子View的长按事件

// 首先需要在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;
        }
    }
});

3 BaseAdapter

png_adapter_uml.png

目前有三种Adapter,两种ViewHolder:

  • BaseByRecyclerViewAdapter(所有adapter超类)
  • BaseRecyclerAdapter (单类型极简adapter)
  • BaseBindingAdapter (使用了databinding的单类型极简adapter)
  • BaseByViewHolder (所有ViewHolder超类)
  • BaseBindingHolder (使用了databinding的ViewHolder)

简单点说:

  • 多类型展示使用BaseByRecyclerViewAdapter,其中使用的ViewHolder可以是BaseByViewHolderBaseBindingHolder
  • 单类型展示使用BaseRecyclerAdapterBaseBindingAdapter,区别是后者使用了databinding

注意:

  • 因为databinding是在编译时生成对应xml文件的类,所以需要使用者拷贝项目中的binding文件夹里的类。

3.1 单类型列表极简实现

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长按事件
    }
}

3.2 单类型列表(databinding)

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);
    }
}

3.3 多类型列表实现

使用 BaseByRecyclerViewAdapter 结合 BaseBindingHolder 或 BaseByViewHolder

public class MultiAdapter extends BaseByRecyclerViewAdapter<DataItemBean, BaseByViewHolder<DataItemBean>> {

    @NonNull
    @Override
    public BaseByViewHolder<DataItemBean> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (11 == viewType) {
            return new ViewHolder2(parent, R.layout.layout_footer_view);
        } else {
            return new ViewHolder(parent, R.layout.layout_empty);
        }
    }

    private class ViewHolder2 extends BaseByViewHolder<DataItemBean> {
        ViewHolder2(ViewGroup viewGroup, int layoutId) {
            super(viewGroup, layoutId);
        }

        @Override
        protected void onBaseBindView(BaseByViewHolder<DataItemBean> holder, DataItemBean bean, int position) {
            holder.setText(R.id.tv_text, bean.getTitle());
        }
    }

    private class ViewHolder extends BaseBindingHolder<DataItemBean, LayoutEmptyBinding> {
        ViewHolder(ViewGroup viewGroup, int layoutId) {
            super(viewGroup, layoutId);
        }

        @Override
        protected void onBindingView(BaseBindingHolder holder, DataItemBean bean, int position) {
           binding.tvText.setText(bean.getTitle());
        }
    }
}

----待续