RecyclerView刷新加载库-SRecyclerView
来源:互联网 发布:多媒体教学软件价格 编辑:程序博客网 时间:2024/06/05 17:36
前言
最近在使用前段时间 “业余时间" 项目中封装的 RecyclerView 时,发现了好几个问题,比如:刷新头部和加载尾部耦合性太高,要是以后想换个刷新头部或加载尾部,必然改动很大,不利于扩展,刷新手势处理和加载更多的逻辑也有点小问题,于是乎,换了一种思路重新封装了一下,核心思想就是:该控件的一些配置,比如刷新头部和加载尾部,刷新头的高度,动画时间等等,都方便扩展和重设置,而且可以很方便的去重写一个刷新头,并且满足某个刷新列表的特殊性要求。封装完成后干脆重命名为SRecyclerView,并上传到JCenter,方便以后更新和维护
功能
主要功能有以下几点
- 下拉刷新,滑到底部加载(也支持GridLayoutManager)
- 支持添加多个头部和尾部(也支持GridLayoutManager)
- 支持代码设置一个刷新头部和加载尾部(某个列表有特殊的刷新头部和加载尾部的需求)
- 支持自定义刷新头部和加载尾部,手势等逻辑已处理,只需写刷新界面逻辑即可
- 可以全局配置刷新头部和加载尾部
- 支持设置LinearLayoutManager的分割线,以及纵向时分割线的左右距离
- 支持设置一个EmptyView
- 支持Item的点击事件
- 附带一个简易的适配器,大大减少适配器的代码
- 默认设置为纵向的LinearLayoutManager
刷新和加载扩展
为了方便扩展刷新头部和加载尾部,这里抽象出一个头部基类 AbsRefreshHeader 和尾部基类 AbsLoadFooter ,在基类中完成一些基础性的操作和逻辑,比如在头部基类 AbsRefreshHeader 中,处理了头部的手势拖拽操作和刷新逻辑,并预留出抽象方法,可以方便子类处理自己的刷新界面的更新,SRecyclerView 中默认实现了一个刷新头部,自己的自定义头部刷新完全可以仿照此实现, 头部基类 AbsRefreshHeader 的代码就不贴了,可以去看源码。我们可以在 init 方法中完成初始化自己的布局,refresh 方法会在整个刷新过程中被调用,按照四种不同的状态更新自己的UI界面,如果需要更改刷新高度(刷新临界值),刷新动画时间,刷新头部的Gravity,可以重写对应的方法,重新设置。
public class TestRefreshHeader extends AbsRefreshHeader { private TextView refreshText; private ClockView clockView; public TestRefreshHeader(Context context) { super(context); } public TestRefreshHeader(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public TestRefreshHeader(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void init() { View view = LayoutInflater.from(getContext()).inflate(R.layout.refresh_view, this, false); clockView = (ClockView) view.findViewById(R.id.v_refresh); refreshText = (TextView) view.findViewById(R.id.tv_refresh); addView(view); } /** * 如果需要设置刷新动画时间,可以重写此方法 */ @Override public int getRefreshDuration() { return 300; } /** * 如果需要设置头部的Gravity,可以重写此方法 * * @return HEADER_CENTER,HEADER_BOTTOM */ @Override public int getRefreshGravity() { return AbsRefreshHeader.HEADER_CENTER;// return AbsRefreshHeader.HEADER_BOTTOM; } /** * 如果需要设置刷新高度,也就是刷新临界值,可以重写此方法 */ @Override public int getRefreshHeight() { return dip2px(70); } private int dip2px(float value) { final float scale = Resources.getSystem().getDisplayMetrics().density; return (int) (value * scale + 0.5f); } /** * SRecyclerView的onDetachedFromWindow被调用,可能SRecyclerView所在的界面要被销毁, * 如果子类中有动画等未完成,可以重写此方法取消动画等耗时操作,避免造成内存泄露 */ @Override public void srvDetachedFromWindow() { if(clockView!=null){ clockView.resetClock(); } } @Override public void refresh(int state, int height) { switch (state) { case NORMAL: refreshText.setText("下拉刷新"); clockView.stopClockAnim(); break; case REFRESH: refreshText.setText("正在刷新..."); clockView.startClockAnim(); break; case PREPARE_NORMAL: refreshText.setText("下拉刷新"); clockView.setClockAngle(height); break; case PREPARE_REFRESH: refreshText.setText("释放立即刷新"); clockView.setClockAngle(height); break; } }}
同样的,如果默认的加载尾部功能或者样式不满足,也可以继承AbsLoadFooter打造项目专属的加载尾部,栗子如下:public class TestLoadFooter extends AbsLoadFooter { private View load, noMore; public TestLoadFooter(Context context) { super(context); } public TestLoadFooter(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public TestLoadFooter(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public void init() { View loadView = LayoutInflater.from(getContext()).inflate(R.layout.srv_load_footer, this, false); noMore = loadView.findViewById(R.id.tv_src_loadNoMore); load = loadView.findViewById(R.id.v_srv_loading); addView(loadView); } @Override public void loadBegin() { load.setVisibility(VISIBLE); noMore.setVisibility(GONE); } @Override public void loadEnd() { load.setVisibility(GONE); noMore.setVisibility(GONE); } /** * 据说有一种需求是,没数据时,直接不显示无数据的UI,此时可设置高度为0,然后重写reset()方法, * 当列表刷新时会重置加载尾部 */ @Override public void loadingNoMoreData() { ViewGroup.LayoutParams params = getLayoutParams(); params.height = 0; setLayoutParams(params); } /** * 刷新结束后如果需要重置加载尾部,可重写此方法重置LoadFooter */ @Override public void reset() { ViewGroup.LayoutParams params = getLayoutParams(); params.height = dip2px(45); setLayoutParams(params); } private int dip2px(float value) { final float scale = Resources.getSystem().getDisplayMetrics().density; return (int) (value * scale + 0.5f); }}
全局配置
那自己实现的头部和尾部怎么一劳永逸的设置给 SRecyclerView 呢?这里我借鉴了 Glide 配置缓存路劲的做法(果然还是大神们厉害),和 Glide 类似,我们新建一个类并实现 SRecyclerViewModule 接口,然后在 AndroidManifest.xml 中配置一下即可,实现原理很简单,每次创建 SRecyclerView 时读取 AndroidManifest.xml 中是否有此配置,如果有此配置则使用,否则使用默认的配置。测试代码如下:
public class TestSRVModule implements SRecyclerViewModule { @Override public AbsRefreshHeader getRefreshHeader(Context context) { return new TestRefreshHeader(context); } @Override public AbsLoadFooter getLoadingFooter(Context context) { return TestLoadFooter(context); } }在 AndroidManifest.xml 中的配置,注意 value 必须为 SRecyclerViewModule<meta-data android:name="com.hzw.srecyclerviewproject.TestSRVModule" android:value="SRecyclerViewModule" />代码里也提供了设置一个刷新头部和加载尾部的方法,主要是为了满足某个列表有特殊刷新样式的需求,具体看github上的代码吧
使用
注意:SRecyclerView中已经导入了support design库(com.android.support:design:xxx),请勿重复导入
混淆
-keep public class * implements com.hzw.srecyclerview.SRecyclerViewModule使用
gradle中添加: compile 'com.github.hzw:srecyclerview:github上的版本'
recyclerView.setLoadListener(new SRecyclerView.LoadListener() { @Override public void refresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { refreshData(); recyclerView.refreshComplete(); } }, 2000); } @Override public void loading() { new Handler().postDelayed(new Runnable() { @Override public void run() { if (list.size() != 30) { loadData(); recyclerView.loadingComplete(); } else { recyclerView.loadNoMoreData(); } } }, 2000); } }); //item的点击事件 recyclerView.setItemClickListener(new SRecyclerView.ItemClickListener() { @Override public void click(View v, int position) { Toast.makeText(getApplication(), "位置: " + position, Toast.LENGTH_SHORT).show(); } }); //可以设置一个EmptyView recyclerView.setEmptyView(emptyView); //可以手动设置一个刷新头部,应该在setAdapter方法之前调用,适用于某个列表需要特殊刷新头的场景 //SRecyclerView的头部设置有两种种方法:代码设置,全局配置。如果两种方法都没有设置,则适用默认自带的默认刷新头和加载尾 //recyclerView.setRefreshHeader(new TestRefreshHeader(this)); //recyclerView.setLoadingFooter(new TestLoadFooter(this)); //这里的适配器使用的一个简易的SRV适配器,同样也可以用于普通的RecyclerView,当然这里也可以用原生的适配器 recyclerView.setAdapter(new SRVAdapter(list)); //recyclerView.setAdapter(new InitAdapter(list, this)); //测试添加头部 View header = LayoutInflater.from(this).inflate(R.layout.header_test, recyclerView, false); recyclerView.addHeader(header); //测试添加尾部 View footer = LayoutInflater.from(this).inflate(R.layout.footer_test, recyclerView, false); recyclerView.addFooter(footer); //SRV的代码刷新,应该在setAdapter方法之后调用,true表示会有刷新动画,false无任何动画 //recyclerView.startRefresh(true);自带的用户简化代码的适配器使用栗子如下,可以看到相比于原生的适配器写法,能减少不少代码,当然这个适配器也可以用于其它的RecyclerView
END/** * 基于简易适配器的写法 */ private static class SRVAdapter extends BaseSRVAdapter<String> { SRVAdapter(List<String> list) { super(list, R.layout.item_test); } @Override public void onBindView(SRVHolder holder, String data, int i) { holder.setTextView(R.id.tv_item_test, data);// holder.setTextView(0, "123")// .setTextView(1, "234"); } }
至此我平常开发中能用到的功能和一些应用场景已尽可能实现,项目已上传到GitHub,library已提交到JCenter上,可以很方便的引用,后续有什么问题,我会及时更新处理。使用方法和注释我在测试代码中写的尽可能详细了,具体看代码吧!
代码:https://github.com/HzwSunshine/SRecyclerView
阅读全文
0 0
- RecyclerView刷新加载库-SRecyclerView
- SRecyclerView
- RecyclerView+OkHttp加载刷新
- RecyclerView的刷新加载
- RecyclerView刷新加载
- RecyclerView 刷新+加载
- RecyclerView解决加载和刷新
- RecyclerView刷新与加载更多
- RecyclerView实现上拉加载,下拉刷新
- RecyclerView 下拉刷新上拉加载更多
- RecyclerView的刷新和加载--XRecyclerView
- RecyclerView实现上拉加载,下拉刷新
- RecyclerView 实现下拉刷新和自动加载
- RecyclerView下拉刷新和加载更多
- RecyclerView 下拉刷新上拉加载更多
- RecyclerView的上拉加载,下拉刷新
- RecyclerView 下拉刷新和上拉加载
- RecyclerView下拉刷新上拉加载
- mysql与oracle数据库创建partition分区脚本
- 初识java
- 土壤含水量
- CentOS7&Nginx环境Let`s Encrypt (HTTPS)证书获取
- Linux添加新硬盘
- RecyclerView刷新加载库-SRecyclerView
- javastruct
- 一个百度产品人对于百度的描述
- Delphi 文件操作(转)
- Lintcode C++代码
- 利用hr和:after伪元素实现hr中间加字
- URLDecoder与URLDecoder的简单了解
- Java SQLServer数据库连接(1)
- 《java编程思想》P125-P140(第七章复用类部分)