我想把ListView改为RecyclerView。我想在RecyclerView中使用OnScrollListener的onScroll来确定用户是否滚动到列表的末尾。
我如何知道用户是否滚动到列表的末尾以便我可以从REST服务获取新数据?
我想把ListView改为RecyclerView。我想在RecyclerView中使用OnScrollListener的onScroll来确定用户是否滚动到列表的末尾。
我如何知道用户是否滚动到列表的末尾以便我可以从REST服务获取新数据?
当前回答
没有重复调用,但你滚动。fetchData只会在您位于列表的末尾并且有更多数据要获取时调用
关于我的代码: 1.fetchData()每次调用取10个项。 2.isScrolling是一个类成员变量 3.previousTotalCount也是类成员。它存储以前访问过的最后一个项目
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val scrolledOutItems = layoutManager.findFirstVisibleItemPosition()
if (isScrolling && (visibleItemCount + scrolledOutItems == totalItemCount)
&& (visibleItemCount + scrolledOutItems != previousTotalCount)) {
previousTotalCount = totalItemCount
isScrolling = false
fetchData() //fetches 10 new items from Firestore
pagingProgressBar.visibility = View.VISIBLE
}
}
})
其他回答
对于使用StaggeredGridLayoutManager的人,这是我的实现,它适用于我。
private class ScrollListener extends RecyclerView.OnScrollListener {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
firstVivisibleItems = mLayoutManager.findFirstVisibleItemPositions(firstVivisibleItems);
if(!recyclerView.canScrollVertically(1) && firstVivisibleItems[0]!=0) {
loadMoreImages();
}
}
private boolean loadMoreImages(){
Log.d("myTag", "LAST-------HERE------");
return true;
}
}
试试下面:
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
/**
* Abstract Endless ScrollListener
*
*/
public abstract class EndlessScrollListener extends
RecyclerView.OnScrollListener {
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 10;
// The current offset index of data you have loaded
private int currentPage = 1;
// True if we are still waiting for the last set of data to load.
private boolean loading = true;
// The total number of items in the data set after the last load
private int previousTotal = 0;
private int firstVisibleItem;
private int visibleItemCount;
private int totalItemCount;
private LayoutManager layoutManager;
public EndlessScrollListener(LayoutManager layoutManager) {
validateLayoutManager(layoutManager);
this.layoutManager = layoutManager;
}
public EndlessScrollListener(int visibleThreshold,
LayoutManager layoutManager, int startPage) {
validateLayoutManager(layoutManager);
this.visibleThreshold = visibleThreshold;
this.layoutManager = layoutManager;
this.currentPage = startPage;
}
private void validateLayoutManager(LayoutManager layoutManager)
throws IllegalArgumentException {
if (null == layoutManager
|| !(layoutManager instanceof GridLayoutManager)
|| !(layoutManager instanceof LinearLayoutManager)) {
throw new IllegalArgumentException(
"LayoutManager must be of type GridLayoutManager or LinearLayoutManager.");
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = layoutManager.getItemCount();
if (layoutManager instanceof GridLayoutManager) {
firstVisibleItem = ((GridLayoutManager) layoutManager)
.findFirstVisibleItemPosition();
} else if (layoutManager instanceof LinearLayoutManager) {
firstVisibleItem = ((LinearLayoutManager) layoutManager)
.findFirstVisibleItemPosition();
}
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading
&& (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
// End has been reached do something
currentPage++;
onLoadMore(currentPage);
loading = true;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page);
}
借助Kotlin扩展函数的强大功能,代码可以看起来更加优雅。把它放在你想要的任何地方(我把它放在一个ExtensionFunctions中。kt文件):
/**
* WARNING: This assumes the layout manager is a LinearLayoutManager
*/
fun RecyclerView.addOnScrolledToEnd(onScrolledToEnd: () -> Unit){
this.addOnScrollListener(object: RecyclerView.OnScrollListener(){
private val VISIBLE_THRESHOLD = 5
private var loading = true
private var previousTotal = 0
override fun onScrollStateChanged(recyclerView: RecyclerView,
newState: Int) {
with(layoutManager as LinearLayoutManager){
val visibleItemCount = childCount
val totalItemCount = itemCount
val firstVisibleItem = findFirstVisibleItemPosition()
if (loading && totalItemCount > previousTotal){
loading = false
previousTotal = totalItemCount
}
if(!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)){
onScrolledToEnd()
loading = true
}
}
}
})
}
然后像这样使用它:
youRecyclerView.addOnScrolledToEnd {
//What you want to do once the end is reached
}
这个解决方案基于Kushal Sharma的回答。然而,这是一个更好的,因为:
它使用onScrollStateChanged而不是onScroll。这样做比较好,因为每当RecyclerView中有任何类型的移动时,onScroll都会被调用,而onScrollStateChanged只在RecyclerView的状态改变时被调用。使用onScrollStateChanged将节省CPU时间,从而节省电池。 因为它使用扩展函数,所以可以在任何RecyclerView中使用。客户端代码只有一行。
没有重复调用,但你滚动。fetchData只会在您位于列表的末尾并且有更多数据要获取时调用
关于我的代码: 1.fetchData()每次调用取10个项。 2.isScrolling是一个类成员变量 3.previousTotalCount也是类成员。它存储以前访问过的最后一个项目
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val scrolledOutItems = layoutManager.findFirstVisibleItemPosition()
if (isScrolling && (visibleItemCount + scrolledOutItems == totalItemCount)
&& (visibleItemCount + scrolledOutItems != previousTotalCount)) {
previousTotalCount = totalItemCount
isScrolling = false
fetchData() //fetches 10 new items from Firestore
pagingProgressBar.visibility = View.VISIBLE
}
}
})
下面是一个简单实现无尽滚动RecyclerView的例子,使用一个从各种来源编译的简单库。
在build.gradle中添加这一行
implementation 'com.hereshem.lib:awesomelib:2.0.1'
在活动中创建RecyclerView布局
<com.hereshem.lib.recycler.MyRecyclerView
android:id="@+id/recycler"
app:layoutManager="LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
通过传递ViewHolder支持的类来创建一个ViewHolder
public static class EVHolder extends MyViewHolder<Events> {
TextView date, title, summary;
public EVHolder(View v) {
super(v);
date = v.findViewById(R.id.date);
title = v.findViewById(R.id.title);
summary = v.findViewById(R.id.summary);
}
@Override
public void bindView(Events c) {
date.setText(c.date);
title.setText(c.title);
summary.setText(c.summary);
}
}
通过在适配器中传递项目、类和布局来创建项目列表变量和很少行的适配器
List<Events> items = new ArrayList<>();
MyRecyclerView recycler = findViewById(R.id.recycler);
RecyclerViewAdapter adapter = new RecyclerViewAdapter(this, items, EVHolder.class, R.layout.row_event);
recycler.setAdapter(adapter);
ClickListener和LoadMore Listener可以通过以下几行添加
recycler.setOnItemClickListener(new MyRecyclerView.OnItemClickListener() {
@Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "Recycler Item Clicked " + position, Toast.LENGTH_SHORT).show();
}
});
recycler.setOnLoadMoreListener(new MyRecyclerView.OnLoadMoreListener() {
@Override
public void onLoadMore() {
loadData();
}
});
loadData();
数据加载后必须调用此函数
recycler.loadComplete();
当不需要LoadMore时,可以通过调用LoadMore来隐藏布局
recycler.hideLoadMore();
更多的例子可以在这里找到
希望这对你有所帮助。