RecyclerView的刷新分页
在开发中常常使用到刷新分页,这里实现一个 RecyclerView 的简单的刷新分页操作,测试效果见文末,实现过程参考如下:
实现思路
- 加载更多数据使用到 RecyclerView 加载多种布局,根据 ViewType 判断加载数据 Item 还是加载 FooterItem ;
- 通过线程模拟加载数据;
- 为 RecyclerView 添加 addOnScrollListener 事件来监听用户的滑动操作;
- 根据用户滑动状态以及具体情况开始加载数据
- 通知数据更新;
如何获得 firstVisibleItemPosition
为了能够在数据加载中动态判断什么时候加载数据,需要知道屏幕上显示的第一个可见的 Item 的位置,当然了这里使用的是布局管理器是 LinearLayoutManager ,这样查找屏幕上第一个可见的 Item 就显得容易多了,下面介绍一些 LinearLayoutManager 的四个方法:
findFirstVisibleItemPosition()
获得屏幕上第一个可见 Item 的 position,只要该 Item 有一部分可见,那么返回的 position 就是该Item 的 position。
findFirstCompletelyVisibleItemPosition()
获得屏幕上第一个完整可见的 Item 的 position,只要该 Item 有一部分不可见,那么返回的 position 就是该 Item 对应的下一个能显示完整的 Item 的position。
findLastVisibleItemPosition()
获得屏幕上最后一个可见 Item 的 position,只要该 Item 有一部分可见,那么返回的 position 就是该Item 的 position。
findLastCompletelyVisibleItemPosition()
获得屏幕上最后一个完整可见的 Item 的 position,只要该 Item 有一部分不可见,那么返回的 position 就是该 Item 对应的上一个能显示完整的 Item 的position。
准备数据
/**
* 初始化数据
* @return
*/
public void initData(){
for (int i=0;i<30;i++){
arrayList.add("第"+i+"条数据");
}
}
/**
* 线程模拟加载数据
*/
class LoadDataThread extends Thread{
@Override
public void run() {
initData();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//通知主线程更新数据
Message message = handler.obtainMessage();
message.what = UPDATE_DATA;
message.obj = arrayList;
handler.sendMessage(message);
}
}
代码参考
主布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.manu.mrecyclerview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
Item布局
/**item.xml**/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<TextView
android:id="@+id/tv_recycle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="data"
android:background="#cac3c3"
android:padding="10dp"
android:textSize="20sp"/>
</LinearLayout>
/**item_footer.xml**/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/progressBar" />
<TextView
android:text="正在努力加载中,请稍后..."
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView" />
</LinearLayout>
Adapter
这里使用了 RecyclerView 根据不同的 ViewType 加载多种布局的用法,使用时根据不同的布局创建不同的 ViewHolder , 然后根据不同的 Viewholder 为对应的 Item 添加数据,注意 getItemViewType() 方法的用法,Adapter 代码参考如下:
/**
* Created by jzman on 2017/6/04
* RecycleView的Adapter
*/
public class RvAdapter1 extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements
View.OnClickListener{
private static final int ITEM_FOOTER = 0x1;
private static final int ITEM_DATA = 0x2;
private Context mContext;
private RecyclerView recyclerView;
private ArrayList<String> mList;
public RvAdapter1() {}
public RvAdapter1(Context mContext, ArrayList<String> mList) {
this.mContext = mContext;
this.mList = mList;
}
public void setmList(ArrayList<String> mList) {
this.mList = mList;
}
/**
* 用于创建ViewHolder
* @param parent
* @param viewTypez
* @return
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view ;
RecyclerView.ViewHolder vh = null;
switch (viewType){
case ITEM_DATA:
view = LayoutInflater.from(mContext).inflate(R.layout.item,null);
view.setOnClickListener(this);
vh = new DataViewHolder(view);
//使用代码设置宽高(xml布局设置无效时)
view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
break;
case ITEM_FOOTER:
view = LayoutInflater.from(mContext).inflate(R.layout.item_footer,null);
//使用代码设置宽高(xml布局设置无效时)
vh = new FooterViewHolder(view);
view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
break;
}
return vh;
}
/**
* 获取Item的View类型
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
//根据 Item 的 position 返回不同的 Viewtype
if (position == (getItemCount())-1){
return ITEM_FOOTER;
}else{
return ITEM_DATA;
}
}
/**
* 绑定数据
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof DataViewHolder){
DataViewHolder dataViewHolder = (DataViewHolder) holder;
dataViewHolder.tv_data.setText(mList.get(position));
}else if (holder instanceof FooterViewHolder){
}
}
/**
* 选项总数
* @return
*/
@Override
public int getItemCount() {
return mList.size()+1;
}
@Override
public void onClick(View view) {
//根据RecyclerView获得当前View的位置
int position = recyclerView.getChildAdapterPosition(view);
//程序执行到此,会去执行具体实现的onItemClick()方法
if (onItemClickListener!=null){
onItemClickListener.onItemClick(recyclerView,view,position,mList.get(position));
}
}
/**
* 创建ViewHolder
*/
public static class DataViewHolder extends RecyclerView.ViewHolder{
TextView tv_data;
public DataViewHolder(View itemView) {
super(itemView);
tv_data = (TextView) itemView.findViewById(R.id.tv_recycle);
}
}
/**
* 创建footer的ViewHolder
*/
public static class FooterViewHolder extends RecyclerView.ViewHolder{
public FooterViewHolder(View itemView) {
super(itemView);
}
}
private OnItemClickListener onItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
/**
* 定义RecyclerView选项单击事件的回调接口
*/
public interface OnItemClickListener{
//参数(父组件,当前单击的View,单击的View的位置,数据)
void onItemClick(RecyclerView parent,View view, int position, String data);
}
/**
* 将RecycleView附加到Adapter上
*/
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
this.recyclerView= recyclerView;
}
/**
* 将RecycleView从Adapter解除
*/
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
this.recyclerView = null;
}
}
MainActivity
这里主要注意 rv.addOnScrollListener(new OnScrollListener() …里面的具体实现,MainActivity 代码参考如下:
/**
* Created by jzman on 2017/6/04 0013.
*/
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_DATA = 0x3;
private RecyclerView rv;
RvAdapter1 adapter;
private ArrayList<String> arrayList = new ArrayList<>();
//加载更多数据时最后一项的索引
private int lastLoadDataItemPosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rv = (RecyclerView) findViewById(R.id.rv);
//设置布局管理器
rv.setLayoutManager(new LinearLayoutManager(this));//线性
// rv.setLayoutManager(new GridLayoutManager(this,4));//线性
// rv.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));//线性
initData();
adapter = new RvAdapter1(this,arrayList);
adapter.setOnItemClickListener(new RvAdapter1.OnItemClickListener() {
@Override
public void onItemClick(RecyclerView parent, View view, int position, String data) {
Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
}
});
rv.addOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == SCROLL_STATE_IDLE &&
lastLoadDataItemPosition == adapter.getItemCount()){
new LoadDataThread().start();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof LinearLayoutManager){
LinearLayoutManager manager = (LinearLayoutManager) layoutManager;
int firstVisibleItem = manager.findFirstVisibleItemPosition();
int l = manager.findLastCompletelyVisibleItemPosition();
lastLoadDataItemPosition = firstVisibleItem+(l-firstVisibleItem)+1;
}
}
});
rv.setAdapter(adapter);
}
/**
* 初始化数据
* @return
*/
public void initData(){
for (int i=0;i<25;i++){
arrayList.add("第"+i+"条数据");
}
}
/**
* 线程模拟加载数据
*/
class LoadDataThread extends Thread{
@Override
public void run() {
initData();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = handler.obtainMessage();
message.what = UPDATE_DATA;
message.obj = arrayList;
handler.sendMessage(message);
}
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case UPDATE_DATA:
arrayList = (ArrayList<String>) msg.obj;
adapter.setmList(arrayList);
adapter.notifyDataSetChanged();
break;
}
}
};
}
测试效果
可关注微信公众号:jzman-blog 获取最新文章更新,一起交流学习!
RecyclerView的刷新分页的更多相关文章
- 在Thinkphp中使用AJAX实现无刷新分页
在Thinkphp目录的Lib\ORG\Util\目录里新建AjaxPage.class.php,写入一下内容: <?php // +------------------------------ ...
- phpcms无刷新分页
控制器添加一个函数: 添加一个静态页面ajax_message.html,在页面中添加如下代码: 在要分页的页面(我的是"show"页面)中添加如上图代码: phpcms无刷新分页 ...
- MVC无刷新分页(即局部刷新,带搜索,页数选择,排序功能)
我查看了很多网站,大部分评论分页都是局部刷新的,可大部分电商商品展示分页都是有刷新页面的,于是我便做了一个商品展示无刷新分页的例子.接下来我就将做一个模仿淘宝已买到的宝贝功能,不过我的是无刷新分页的. ...
- 扩展GridView实现的一个自定义无刷新分页,排序,支持多种数据源的控件TwfGridView
最近项目View层越来越趋向于无刷新化,特别是数据展示方面,还要对Linq有很好的支持.在WebFrom模式的开发中,GridView是一个功能很强大,很常用的控件,但是他也不是完美的,没有自带的无刷 ...
- ajax 无刷新分页
//ajax 无刷新分页1.前台要做的 滑动时 当前page+1,通过page ajax请求后台接口获取数据将数据进行拼装;2.后台要做的 做分页接口返回json数据前台判断触发请求条件: var p ...
- thinkphp ajax 无刷新分页效果的实现
思路:先做出传统分页效果,然后重新复制一份Page.class.php类,对它进行修改,把js中的函数传到page类中,把上一页.下一页.首页.尾页.链接页中的url地址改成js控制的函数,模板页面中 ...
- Ajax+Asp.Net无刷新分页
1.新建解决方案,并建立四个项目BLL,DAL,Model,PagerTest,如图所示: 2.Model代码 using System; using System.Collections.Gener ...
- ASP.NET Ajax简单的无刷新分页
最近练习了一些AJAX无刷新分页,写得比较简单,性能不知道怎么样,求大神指点,如有更好的分页提供,欢迎交流! 发话不多说了,直接上代码! 首先从网上下了一个JS分页,感觉挺好用的 (function( ...
- 无刷新分页 jquery.pagination.js
无刷新分页 jquery.pagination.js 采用Jquery无刷新分页插件jquery.pagination.js实现无刷新分页效果 1.插件参数列表 http://www.dtan.so ...
随机推荐
- 初识 jquery.simulate.js 模拟键盘事件
用jquery 和 jquery.simulate.js 实现模拟键盘事件,点击上下左右div相当于点击键盘的上下左右键 <!DOCTYPE html> <html> < ...
- PHPRAP 1.0.2 发布,修复安装失败 Bug 和优化细节
PHPRAP,是一个PHP轻量级开源API接口文档管理系统,致力于减少前后端沟通成本,提高团队协作开发效率,打造PHP版的RAP. 更新记录 [修复]修复在MySQL5.5版本下安装数据初始化sql文 ...
- 微信h5页面audio标签在ios下不能自动播放
背景介绍:在一个h5页面中,当用户提交表单到后台,后台返回的结果成功的话,开始自动播放背景音乐 出现的问题:在安卓手机上正常,iOS中没有反应 后来网上一番搜索后了解到时因为iOS不允许自动播放音乐, ...
- LeetCode 278.First Bad Version(E)(P)
题目: You are a product manager and currently leading a team to develop a new product. Unfortunately, ...
- ubuntu下pip的安装,更新及卸载
在Ubuntu下,不小心uninstall pip了,然后呢,作为小白的我,还是有些着急的,用了一些方法不好使,最后找到了这个方法: 1.安装pip3: sudo apt-get install py ...
- python——字符串截取
str = ‘0123456789’ print str[0:3] #截取第一位到第三位的字符 print str[:] #截取字符串的全部字符 print str[6:] #截取第七个字符到结尾 p ...
- Python正则表达式语法
单个字符匹配 字符 匹配 . 匹配任意字符(除了\n) [...] 匹配字符集 \d/\D 匹配数字/非数字 \s/\S 匹配空白/非空白字符 \w/\W 匹配单词字符[a-zA-A0-9] In [ ...
- C#版免费离线人脸识别——虹软ArcSoft V3.0
[温馨提示] 本文共678字(不含代码),8张图.预计阅读时间需要6分钟. 1. 前言 人脸识别&比对发展到今天,已经是一个非常成熟的技术了,而且应用在生活的方方面面,比如手机.车站.天网等. ...
- 0312 java接口测试三棱军刺rest-assured
背景 java程序员一般写的是后端服务是JavaWeb类型的项目,主要包括Http接口和dubbo接口,Http接口一般采用的rest风格,那么如何快速的对rest接口在第三方的测试框架上进行测试呢? ...
- openwrt 外挂usb 网卡 RTL8188CU 及添加 RT5572 kernel支持
RT5572 原来叫 Ralink雷凌 现在被 MTK 收购了,淘宝上买的很便宜50块邮,2.4 5G 双频.在 win10 上插了试试,果然是支持 5G.这上面写着 飞荣 是什么牌子,有知道的和我说 ...