实现onScrollListener来检测ListView中的滚动结束

我有一个ListView显示一些项目。 我想对当前显示在ListView的可见部分中的项目执行一些操作,具体取决于ListView如何滚动; 因此我想实现ListViewOnScrollListener 。 根据Android API参考,onScroll方法“将在滚动完成后调用”。 这在我看来是正确的,因为一旦滚动完成,我在ListView上执行我的操作(onScroll方法返回显示的第一个项目的索引和显示的项目数)。

但是一旦实现,我从LogCat中看到onScroll方法不仅在滚动完成后触发,而且从滚动的开始到结束,每进入一个显示视图的新项目都会触发onScroll方法。 这不是我所期望的行为,也不是我所需要的。 监听器的另一种方法(onScrollStateChanged)不提供有关当前在ListView显示的项目的信息。

那么,有没有人知道如何使用这几个方法来检测滚动的结尾,并获得有关显示项目的信息? API参考和方法的实际行为之间的不一致让我困惑了一下。 提前致谢。

PS:我已经看到了一些类似的话题,但没有任何帮助我理解整个事情是如何工作的。

最后,我已经达成了一个不那么高雅的解决scheme,但是这对我来说很有效。 已经知道onScroll方法被称为滚动的每一个步骤,而不是只是在滚动结束调用,而onScrollStateChanged实际上是只有当滚动完成时调用,我做这样的事情:

 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.currentFirstVisibleItem = firstVisibleItem; this.currentVisibleItemCount = visibleItemCount; } public void onScrollStateChanged(AbsListView view, int scrollState) { this.currentScrollState = scrollState; this.isScrollCompleted(); } private void isScrollCompleted() { if (this.currentVisibleItemCount > 0 && this.currentScrollState == SCROLL_STATE_IDLE) { /*** In this way I detect if there's been a scroll which has completed ***/ /*** do the work! ***/ } } 

实际上,每当ListView被滚动时,我保存关于第一个可见项目和可见项目计数(onScroll方法)的数据。 当滚动状态改变(onScrollStateChanged)我保存状态,我调用另一种方法,实际上了解是否有一个滚动,如果它完成。 通过这种方式,我也有关于我需要的可见项目的数据。 也许不干净,但工作!

问候

 @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (list.getLastVisiblePosition() == list.getAdapter().getCount() - 1 && list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) { //scroll end reached //Write your code here } } 
 @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if((firstVisibleItem + visibleItemCount) == totalItemCount) { Log.i("Info", "Scroll Bottom" ); } }}); 

为了减less这种行为是棘手的,并花了我一段时间来完善。 问题的关键是,据我所知,滚动听众本身并不足以检测到“滚动停止”(包括方向button/轨迹球)。 我最终做了一些正确的事情,就像我期待的那样。

我想我能做到的最好的方法是扩展ListView并覆盖一些方法:

  .... @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) { startWait(); } return super.onKeyUp(keyCode, event); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { stopWait(); } if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { startWait(); } return super.onTouchEvent(event); } private OnScrollListener customScrollListener = new OnScrollListener() { @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { stopWait(); } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) { startWait(); } else { stopWait(); } } }; //All this waiting could be improved, but that's the idea private Thread waitThread = null; private int waitCount = Integer.MIN_VALUE; public void stopWait() { waitCount = Integer.MIN_VALUE; } public synchronized void startWait() { waitCount = 0; if (waitThread != null) { return; } waitThread = new Thread(new Runnable() { @Override public void run() { try { for (; waitCount.get() < 10; waitCount++) { Thread.sleep(50); } //Kick it back to the UI thread. view.post(theRunnableWithYourOnScrollStopCode); // HERE IS WHERE YOU DO WHATEVER YOU WANTED TO DO ON STOP } catch (InterruptedException e) { } finally { waitThread = null; } } }); waitThread.start(); } 

请注意,您还必须在构造函数中绑定customScrollListener 。 我认为这个实现是很好的,因为它不会立即触发“事件”,它将等待一段时间,直到它实际完全停止滚动。

试试这个…

 @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int position = firstVisibleItem+visibleItemCount; int limit = totalItemCount; // Check if bottom has been reached if (position >= limit && totalItemCount > 0) { //scroll end reached //Write your code here } } 

电子卡尔的答案只是更有用的代表

监听器实现:

 public abstract class OnScrollFinishListener implements AbsListView.OnScrollListener { int mCurrentScrollState; int mCurrentVisibleItemCount; @Override public void onScrollStateChanged(AbsListView view, int scrollState) { mCurrentScrollState = scrollState; if (isScrollCompleted()) { onScrollFinished(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { mCurrentVisibleItemCount = visibleItemCount; } private boolean isScrollCompleted() { return mCurrentVisibleItemCount > 0 && mCurrentScrollState == SCROLL_STATE_IDLE; } protected abstract void onScrollFinished(); } 

用法:

  listView.setOnScrollListener(new OnScrollFinishListener() { @Override protected void onScrollFinished() { // do whatever you need here! } }); 

分析以前的答案,find了自己的:

在onViewCreated,onCreate或任何你抓住你的列表视图:

 ListView list = (ListView) view.findViewById(R.id.[your id]); list.setOnScrollListener(this); 

然后填写监听器方法:

 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // yes, just leave it empty } public void onScrollStateChanged(AbsListView view, int scrollState) { this.isScrollCompleted(view, scrollState); } private void isScrollCompleted(AbsListView view, int scrollState) { if (!view.canScrollVertically(1) && this.currentScrollState == SCROLL_STATE_IDLE) { // do work } } 

似乎它应该做的:检测列表的末尾没有吨代码和适配器的修改。

还有一个更简单的解决scheme。 把一个监听器的ListView的适配器,并在getview中检查是否(位置== totalItemCount的项目在数组中显示),如果是我从适配器和监听器调用我的监听器无论它是什么运行

当我试图找出列表是否位于OnScrollListener的底部时,遇到了很多问题,我发现最好的解决scheme是从适配器的getView方法中检查,如果我正在显示最后一行:

 @Override public View getView(int position, View convertView, ViewGroup parent) { ActivityView view; if (convertView==null) view = (ActivityView)inflater.inflate(R.layout.activity_item, null); else view = (ActivityView)convertView; view.showRow(activitiesList.get(position),position,controller,this); if(position == activitiesList.size() - 1) { Log.i("BOTTOM","reached"); } return view; } 

在那里我可以很容易地创build一个接口来通知我到达底部的片段/活动。

干杯。