ListView之滚动事件--OnScrollListener
在 onScrollStateChanged ( AbsListView view, int scrollState) 中,scrollState有三种状态,分别是开始滚动( SCROLL_STATE_FLING ),正在滚动( SCROLL_STATE_TOUCH_SCROLL ), 已经停止( SCROLL_STATE_IDLE ),对于滚动事件的处理,很有必要知道。
ListView继承自AbsListView
AbsListView中有一个滚动事件的Listenter,如下:
public interface OnScrollListener {
/**
* The view is not scrolling. Note navigating the list using the trackball counts as
* being in the idle state since these transitions are not animated.
*/
public static int SCROLL_STATE_IDLE = 0;
/**
* The user is scrolling using touch, and their finger is still on the screen
*/
public static int SCROLL_STATE_TOUCH_SCROLL = 1;
/**
* The user had previously been scrolling using touch and had performed a fling. The
* animation is now coasting to a stop
*/
public static int SCROLL_STATE_FLING = 2;
/**
* Callback method to be invoked while the list view or grid view is being scrolled. If the
* view is being scrolled, this method will be called before the next frame of the scroll is
* rendered. In particular, it will be called before any calls to
* {@link Adapter#getView(int, View, ViewGroup)}.
*
* @param view The view whose scroll state is being reported
*
* @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
* {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
*/
public void onScrollStateChanged(AbsListView view, int scrollState);
/**
* Callback method to be invoked when the list or grid has been scrolled. This will be
* called after the scroll has completed
* @param view The view whose scroll state is being reported
* @param firstVisibleItem the index of the first visible cell (ignore if
* visibleItemCount == 0)
* @param visibleItemCount the number of visible cells
* @param totalItemCount the number of items in the list adaptor
*/
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount);
}
****************************************************************************************************************************************
private boolean mBusy=false; //滚动中
private OnScrollListener mOnScrollListener = new OnScrollListener(){
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
mBusy = false;
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
mBusy = true;
break;
case OnScrollListener.SCROLL_STATE_FLING:
mBusy = true;
break;
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
};
****************************************************
OnScrollListener还可以方便的实现动态加载数据。
遇到问题要多思考。多动脑,少动手~~!
import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.widget.AbsListView;import android.widget.ArrayAdapter;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.AbsListView.OnScrollListener;public class ListViewActivity extends Activity { private ListView lv; private List<String> list; private int lastItem; private int listSize; private ListAdapter adapter; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView) findViewById(R.id.lv); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, getData()); lv.setAdapter(adapter); lv.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView paramAbsListView, int paramInt) { //当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1; //由于用户的操作,屏幕产生惯性滑动时为2 System.out.println("***lastItem:"+lastItem); System.out.println("***listSize:"+listSize); if(lastItem == listSize){ System.out.println("**************"); //数据全部显示出来时运行此处代码,如果要实现分页功能,在这里加载下一页的数据 } } @Override public void onScroll(AbsListView paramAbsListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {// // firstVisibleItem表示在现时屏幕第一个ListItem(部分显示的ListItem也算)// // 在整个ListView的位置(下标从0开始) // System.out.println("***firstParamInt:"+firstVisibleItem);// // visibleItemCount表示在现时屏幕可以见到的ListItem(部分显示的ListItem也算)总数// System.out.println("***visibleItemCount:"+visibleItemCount);// // totalItemCount表示ListView的ListItem总数// System.out.println("***totalItemCount:"+totalItemCount); // listView.getLastVisiblePosition()表示在现时屏幕最后一个ListItem(最后ListItem要完全 // 显示出来才算)在整个ListView的位置(下标从0开始)// System.out.println("****"+String.valueOf(lv.getLastVisiblePosition())); lastItem = lv.getLastVisiblePosition(); } }); } private List<String> getData(){ int i; list = new ArrayList<String>(); for(i=1; i<10; i++){ list.add("ListView"+i); } listSize = list.size()-1; return list; }} 如果还有什么不懂的,见意去看下源码。
OnScrollListener回调分析
如果adapter中的数据量很大的时候,在加载listview时会出现卡顿的现象。这是会让用户抓狂!最好的解决办法就是先加载一定数量的数据,然后在最下方提示正在加载!
动态加载就是把放入adapter中的数据分好几次加载。在用户拖动listview时再加载一定的数据,和sina微博的客户端类似。
给listview添加OnScrollListener监听事件默认会覆盖下面两个方法:
Java代码
- 1.new OnScrollListener() {
- 2. boolean isLastRow = false;
- 3.
- 4. @Override
- 5. public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- 6. //滚动时一直回调,直到停止滚动时才停止回调。单击时回调一次。
- 7. //firstVisibleItem:当前能看见的第一个列表项ID(从0开始)
- 8. //visibleItemCount:当前能看见的列表项个数(小半个也算)
- 9. //totalItemCount:列表项共数
- 10.
- 11. //判断是否滚到最后一行
- 12. if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
- 13. isLastRow = true;
- 14. }
- 15. }
- 16. @Override
- 17. public void onScrollStateChanged(AbsListView view, int scrollState) {
- 18. //正在滚动时回调,回调2-3次,手指没抛则回调2次。scrollState = 2的这次不回调
- 19. //回调顺序如下
- 20. //第1次:scrollState = SCROLL_STATE_TOUCH_SCROLL(1) 正在滚动
- 21. //第2次:scrollState = SCROLL_STATE_FLING(2) 手指做了抛的动作(手指离开屏幕前,用力滑了一下)
- 22. //第3次:scrollState = SCROLL_STATE_IDLE(0) 停止滚动
- 23.
- 24. //当滚到最后一行且停止滚动时,执行加载
- 25. if (isLastRow && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
- 26. //加载元素
- 27. ......
- 28.
- 29. isLastRow = false;
- 30. }
- 31. }
- 32.}
一片国外的翻译文档,但是不是很正确
[url=]onScrollListener实施检测在ListView滚动年底[/url]
我ListView ListView显示一些项目。我想执行一些当前显示中的可见部分的项目ListView ListView,如何ListView中一直滚动,因此我认为OnScrollListener ListView ListView的。因此到Android API参考,onScroll法“将被称为滚动后已经完成”。这在我看来,我需要的东西,因为一旦滚动完成后,我在执行我的行动ListView (onScroll方法返回显示的第一项指数和显示的项目数)。
但是,一旦实施,我看到LogCat LogCat onScroll方法,不只是发射一次滚动已完成,但发射进入显示视图为每一个新项目,从开始到结束滚动。这不是我所期望的行为,也没有我需要的。 ,而不是其他的侦听器的方法(onScrollStateChanged)不提供有关在当前显示的项目的ListView ListView 。
所以,没有人知道如何使用这两个方法来检测滚动的结束,并得到所显示的项目信息?之间的API参考资料和实际行为的方法不对,弄得我有点。预先感谢。
PS:我已经看到了一些类似的主题周围,但没有帮助我了解整个事情的作品..!
[url=]回答[/url] [url=]1[/url] 为了获得这一行为向下是棘手的,我花了相当长一段时间来完善。肉的问题是,自己的滚动听众是不是真的很足以探测到一个“滚动停止”(包括方向键/轨迹球),至于我可以告诉。我结束了作品的权利,我希望它做的事情结合。
我想我能做到这一点的最好办法是延长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();} {stopWait();}}} / /所有这个等待可能得到改善,但是这想法私人主题waitThread = NULL;私人诠释waitCount = Integer.MIN_VALUE的;公共无效stopWait(){waitCount = Integer.MIN_VALUE的;}市民同步无效startWait(){waitCount = 0;(waitThread = NULL){;} waitThread =新主题(新的Runnable(){@覆盖公共无效的run() {尝试{(; waitCount.get()<10; waitCount + +){Thread.sleep代码(50);} / /踢它返回到UI线程view.post(theRunnableWithYourOnScrollStopCode); / /这里是你办什么你想要做关于停止}赶上(InterruptedException E){} {waitThread = NULL;}}}); waitThread.start();}请注意,您还可以customScrollListener customScrollListener在你的构造。这种实现是不错的,我觉得,因为它不会立即火“事件”,它会稍等一会,直到它实际上已经完全停止滚动。
[url=]2[/url] 在年底,我已经达到了一个解决方案,没有那么多优雅的,但为我工作;想通了,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! ***/ } } *** / 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)我保存的状态和我调用另一个方法,这实际上是了解是否有一个滚动的,如果它的完成。这样,我也有可见项目,我需要的数据。也许不干净,但作品!
关于
如果adapter中的数据量很大的时候,在加载listview时会出现卡顿的现象。这是会让用户抓狂!最好的解决办法就是先加载一定数量的数据,然后在最下方提示正在加载! 动态加载就是把放入adapter中的数据分好几次加载。在用户拖动listview时再加载一定的数据,和sina微博的客户端类似。
给listview添加OnScrollListener监听事件默认会覆盖下面两个方法:
Java代码 收藏代码
OnScrollListener loadListener=new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
lastItem = firstVisibleItem + visibleItemCount;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
//listview滚动时会执行这个方法,这儿调用加载数据的方法。
adapter.notifyDataSetChanged();//提醒adapter更新
uList.setSelection(lastItem - 1);//设置listview的当前位置,如果不设置每次加载完后都会返回到list的第一项。
}
}
};
TIP:
1、如果activity中只有listview,当listview的数据量很大时,在启动activity时会卡顿半天知道数据加载完可以显示,这时可以可以用handler,将加载数据的操作写在handler里面,而且要在onResume()方法中执行,放在onCreate()不起作用。
2、如果是从网络获取数据,或者数据量很大可以新开一个线程,在线程中完成数据的加载。
3、如果添加的加载提示框出不来,可能是加载过程一直占有cpu,无法显示提示框,可以将加载的代码写到handler里面,用postDelayed()方法给一定的时间延迟去加载数据。
监听ListView滚动到最底部
监听ListView的滚动可以用两个东西:
- ListView.onScrollStateChanged (本文讲解这个listener的使用)
- 在OnGestureListener类里面的onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) 事件
List9介绍的是ListView.OnScrollListener的 onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 方法。
List13介绍的是ListView.OnScrollListener的 onScrollStateChanged(AbsListView view, int scrollState) 方法,使用说明如下:
ListView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, intscrollState) { switch (scrollState) { case OnScrollListener.SCROLL_STATE_IDLE: Log.v("已经停止:SCROLL_STATE_IDLE"); break; case OnScrollListener.SCROLL_STATE_FLING: Log.v("开始滚动:SCROLL_STATE_FLING"); break; case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: Log.v("正在滚动:SCROLL_STATE_TOUCH_SCROLL"); break; } } @Override public void onScroll(AbsListView view,int firstVisibleItem, int visibleItemCount, int totalItemCount) { }});
监听ListView滚动到最底部使用 onScrollStateChanged(AbsListView view, int scrollState) 方法,代码大致如下:
// 监听listview滚到最底部mIndexList.setOnScrollListener(new OnScrollListener() { @Override public voidonScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { // 当不滚动时 caseOnScrollListener.SCROLL_STATE_IDLE: // 判断滚动到底部 if (view.getLastVisiblePosition() == (view.getCount() - 1)) { isLastisNext++; } break; } } @Override public voidonScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { }});
我使用这个发现两个问题:
- 在模拟器上,如果使用鼠标的滚轮来滚动时执行 onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) 方法,不执行 onScrollStateChanged(AbsListView view, int scrollState) 方法。只有触摸往下滑动时,才执行onScrollStateChanged(AbsListView view, int scrollState) 方法。有待考证。
- SCROLL_STATE_TOUCH_SCROLL一定执行,然后下面可能执行SCROLL_STATE_FLING,也可能执行SCROLL_STATE_IDLE。这个是不确定的。有待考证。