文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android代码实现AdapterViews和RecyclerView无限滚动

2022-06-06 08:10

关注

应用的一个共同的特点就是当用户欢动时自动加载更多的内容,这是通过用户滑动触发一定的阈值时发送数据请求实现的。
相同的是:信息实现滑动的效果需要定义在列表中最后一个可见项,和某些类型的阈值以便于开始在最后一项到达之前开始抓取数据,实现无限的滚动。
实现无限滚动的现象的重要之处就在于在用户滑动到最低端之前就行数据的获取,所以需要加上一个阈值来帮助实现获取数据的预期。

使用ListView和GridView实现

每个AdapterView 例如ListView 和GridView 当用户开始进行滚动操作时候都会触发OnScrollListener .使用这个系统我们就可以定义一个基本的EndlessScrollListener ,通过创造继承OnScrollListener 的类来支持大多数情况下的使用。


package com.codepath.customadapter;
import android.widget.AbsListView;

public abstract class EndlessScrollListener implements AbsListView.OnScrollListener {
 //在你滑动项下最少为多少时开始加载数据
 private int visibleThreshold = 5;
 //已经加载数据的当前页码
 private int currentPage = 0;
 //上一次加载数据后数据库的数据量
 private int previousTotalItemCount = 0;
 //我们是否在等待最后一组数据的加载
 private boolean loading = true;
 //设置开始页的下标
 private int startingPageIndex = 0;
 public EndlessScrollListener() {
 }
 public EndlessScrollListener(int visibleThreshold) {
  this.visibleThreshold = visibleThreshold;
 }
 public EndlessScrollListener(int visibleThreshold, int startingPageIndex) {
  this.visibleThreshold = visibleThreshold;
  this.startingPageIndex = startingPageIndex;
 }
 //这个方法可能会在滑动调用很多次,所以在设计时要保持谨慎
 //我们需要一些有用的参数来帮助我们,当我们需要加载更多数据的时候
 //但是我们首先要检查是否我们在等待先前的加载结束
//onScroll()当列表或网格视图被滚动后将会调用,参数一:报告状态的视图参数二:第一个可以看见的项的下标,参数三:可见项的数量参数四:listAdapter中所有的项数
 @Override
 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  //如果总项数为0,而且先前没有项,那么这个列表是无效的应该被设定为初始状态
  if (totalItemCount < previousTotalItemCount) {
   this.currentPage = this.startingPageIndex;
   this.previousTotalItemCount = totalItemCount;
   if (totalItemCount == 0) {this.loading = true;}
  }
  //如果仍在加载中我们可以检查一下数据集合是否改变了,如果改变的话那就是已经完成了loading需要更新当前
  //页数和数据总量
  if (loading && (totalItemCount > previousTotalItemCount)) {
   loading = false;
   previousTotalItemCount = totalItemCount;
   currentPage++;
  }
  //如果当前没有加载,我们需要检查当前是否达到了阈值,如果是的话我们需要
  //加载更多的数据,执行onLoadMore
  if (!loading && (firstVisibleItem + visibleItemCount + visibleThreshold) >= totalItemCount) {
   loading = onLoadMore(currentPage + 1, totalItemCount);
  }
 }
 //定义实际加载数据的过程,如果数据加载完成返回false,如果正在加载返回true;
 public abstract boolean onLoadMore(int page, int totalItemCount);
 @Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  //不采取动作
 }
}

要注意的是这是一个抽象的类,为了要使用这些,必须继承这个基本的类并且实现onLoadMore()方法实际的获取数据, 我们在一个活动中定义一个匿名的类来继承EndlessScrollListener然后将其连接AdapterView上


public class MainActivity extends Activity {
 @Override
 protected void onCreate(Bundle savedInstance) {
  //向平常一样
   ListView lvItems = (ListView) findViewById(R.id.lvItens);
   //将监听器绑定到上面
    lvItems.setOnScrollListener(new EndlessScrollListener() {
   @Override
   public boolean onLoadMore(int page, int totalItemsCount) {
    // 当新数据需要绑定到列表上的时候触发
    // 加载数据需要的代码Add whatever code is needed to append new items to your AdapterView
    customLoadMoreDataFromApi(page); 
    // or customLoadMoreDataFromApi(totalItemsCount); 
    return true; //数据加载中为true,不然为false; ONLY if more data is actually being loaded; false otherwise.
   }
  });
 }
 //加载更多的数据
 public void customLoadMoreDataFromApi(int offset) {
  //这个方法通常会发起一些网络请求,然后向适配器添加更多的数据
  //将偏移量数据作为参数附在请求里来获得一个数据的分页
  //解析API返回的值并且获得新的对象构建适配器
 }
}

现在当用户滑动并且触发阈值时会自动触发onloadMore() 方法,而且监听器给予了对于页数和数据总量的访问权限。

实现RecyclerView的无限滑动

我们可以使用相同的方法来定义一个接口EndlessRecyclerViewScrollListener 然后定义一个onLoadMore() 的方法来进行实现。由于LayoutManager负责项的生成和滑动的管理,我们需要一个LayoutManage的实例来收集必要的信息。
实现必要的分页需要这样的步骤:
1).直接复制EndlessRecyclerViewScrollListener.java
2).调用addOnScrollListener(...) 在RecyclerView 中来实现无限的分页,传递EndlessRecyclerViewScrollListener的实例来实现onLoadMore 方法来决定什么时候来加载新的数据
3).在onLoadMore 方法中通过发送网络请求或者从源数据加载来获得更多item。


 protected void onCreate(Bundle savedInstanceState) {
  // Configure the RecyclerView获得RecylerView的实例
  RecyclerView rvItems = (RecyclerView) findViewById(R.id.rvContacts);
  LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
  recyclerView.setLayoutManager(linearLayoutManager);
  // Add the scroll listener
  rvItems.addOnScrollListener(new EndlessRecyclerViewScrollListener(linearLayoutManager) {
   @Override
   public void onLoadMore(int page, int totalItemsCount) {
    // Triggered only when new data needs to be appended to the list
    // Add whatever code is needed to append new items to the bottom of the list
    customLoadMoreDataFromApi(page); 
   }
  });
 }
 // Append more data into the adapter
 // This method probably sends out a network request and appends new data items to your adapter. 
 public void customLoadMoreDataFromApi(int page) {
  // Send an API request to retrieve appropriate data using the offset value as a parameter.
  // --> Deserialize API response and then construct new objects to append to the adapter
  // --> Notify the adapter of the changes
 }
}

EndlessRecyclerView


public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener {
 // The minimum amount of items to have below your current scroll position
 // before loading more.
 private int visibleThreshold = 5;
 // The current offset index of data you have loaded
 private int currentPage = 0;
 // The total number of items in the dataset after the last load
 private int previousTotalItemCount = 0;
 // True if we are still waiting for the last set of data to load.
 private boolean loading = true;
 // Sets the starting page index
 private int startingPageIndex = 0;
 RecyclerView.LayoutManager mLayoutManager;
 public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
  this.mLayoutManager = layoutManager;
 }
 public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
  this.mLayoutManager = layoutManager;
  visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
 }
 public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
  this.mLayoutManager = layoutManager;
  visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
 }
 public int getLastVisibleItem(int[] lastVisibleItemPositions) {
  int maxSize = 0;
  for (int i = 0; i < lastVisibleItemPositions.length; i++) {
   if (i == 0) {
    maxSize = lastVisibleItemPositions[i];
   }
   else if (lastVisibleItemPositions[i] > maxSize) {
    maxSize = lastVisibleItemPositions[i];
   }
  }
  return maxSize;
 }
 // This happens many times a second during a scroll, so be wary of the code you place here.
 // We are given a few useful parameters to help us work out if we need to load some more data,
 // but first we check if we are waiting for the previous load to finish.
 @Override
 public void onScrolled(RecyclerView view, int dx, int dy) {
  int lastVisibleItemPosition = 0;
  int totalItemCount = mLayoutManager.getItemCount();
  if (mLayoutManager instanceof StaggeredGridLayoutManager) {
   int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
   // get maximum element within the list
   lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
  } else if (mLayoutManager instanceof LinearLayoutManager) {
   lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
  } else if (mLayoutManager instanceof GridLayoutManager) {
   lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
  }
  // If the total item count is zero and the previous isn't, assume the
  // list is invalidated and should be reset back to initial state
  if (totalItemCount < previousTotalItemCount) {
   this.currentPage = this.startingPageIndex;
   this.previousTotalItemCount = totalItemCount;
   if (totalItemCount == 0) {
    this.loading = true;
   }
  }
  // If it's still loading, we check to see if the dataset count has
  // changed, if so we conclude it has finished loading and update the current page
  // number and total item count.
  if (loading && (totalItemCount > previousTotalItemCount)) {
   loading = false;
   previousTotalItemCount = totalItemCount;
  }
  // If it isn't currently loading, we check to see if we have breached
  // the visibleThreshold and need to reload more data.
  // If we do need to reload some more data, we execute onLoadMore to fetch the data.
  // threshold should reflect how many total columns there are too
  if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
   currentPage++;
   onLoadMore(currentPage, totalItemCount);
   loading = true;
  }
 }
 // Defines the process for actually loading more data based on page
 public abstract void onLoadMore(int page, int totalItemsCount);
}

注意问题:
 1.对于ListView,确定将绑定监听器的步骤放在onCreate()的方法中
 2.为可加可靠的进行分页,需要确定在向列表中添加新数据的时候先清理适配器中的数据
对于RecyclerView来说在通知适配器时推荐更细致的更新。
 3.对于RecyclerView来说确保在清除列表中的数据的时候迅速的通知适配器内容更新了,以便于可以触发新的onScroll事件,重置自己 

展示进度条

为了在底部展示进度条证明ListView正在加载。我们可以在Adapter中进行设置,我们可以定义两类,可以是进度条类型或者是文本表明达到了最底行,参考:http://guides.codepath.com/android/Endless-Scrolling-with-AdapterViews-and-RecyclerView

您可能感兴趣的文章:RecyclerView实现抖音纵向滚动ViewPager效果Android 基于RecyclerView实现的歌词滚动自定义控件Android RecyclerView 滚动到中间位置的方法示例浅谈Android RecyclerView UI的滚动控件示例Android RecyclerView 实现快速滚动的示例代码功能强大的Android滚动控件RecyclerViewAndroid使用Recyclerview实现图片水平自动循环滚动效果XRecyclerView实现下拉刷新、滚动到底部加载更多等功能Android_RecyclerView实现上下滚动广告条实例(带图片)Android中RecyclerView实现分页滚动的方法详解Android RecyclerView滚动定位Android使用RecyclerView实现水平滚动控件RecyclerView实现纵向和横向滚动


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯