在实现ListView下拉弹起效果,最重要的是如何监听到ListView的底部及顶部,AbstractListViewtrackMotionScroll(int,int)方法中,分析出ListView是如何判断滑动到底部及顶部的方法。

private boolean isHeader(int deltay) {     int firstTop = getChildAt(0).getTop();     int effectivePaddingTop = getListPaddingTop();     int spaceAbove = effectivePaddingTop - firstTop;     return getFirstVisiblePosition() == 0&&spaceAbove<=0&&deltay<0;   }   private boolean isButtom(int deltay) {      int lastBottom = getChildAt(getChildCount() - 1).getBottom();      int effectivePaddingBottom = getListPaddingBottom();      return getLastVisiblePosition() == (getCount() - 1)&&lastBottom<=(getHeight()-effectivePaddingBottom)&&deltay>0;   }   

通过以上两个方法可以判断ListView是否滑动到底部及顶部。
但是为了实现弹起效果,必须用到scrollBy()和scrollTo()两个方法。具体实现代码如下:

import android.content.Context;   import android.os.Handler;   import android.util.AttributeSet;   import android.view.MotionEvent;   import android.widget.ListView;   import android.widget.Scroller;   public class MyListView extends ListView {   private Context mContext;   private Scroller mScroller;   private int mLastMotionY = 0;   public MyListView(Context context, AttributeSet attrs, int defStyle) {     super(context, attrs, defStyle);     // TODO Auto-generated constructor stub   }   public MyListView(Context context, AttributeSet attrs) {     super(context, attrs);     this.mContext = context;     mScroller = new Scroller(mContext);   }   public MyListView(Context context) {     super(context);     // TODO Auto-generated constructor stub   }   @Override   public void computeScroll() {     if (mScroller.computeScrollOffset()) {      scrollTo(mScroller.getCurrX(), mScroller.getCurrY());      postInvalidate();     }   }   @Override   public boolean dispatchTouchEvent(MotionEvent event) {     // TODO Auto-generated method stub     int y = (int) event.getY();     switch (event.getAction()) {     case MotionEvent.ACTION_DOWN:      if (mScroller != null) {       if (!mScroller.isFinished()) {        mScroller.abortAnimation();       }      }      mLastMotionY = y;      break;     case MotionEvent.ACTION_MOVE:      int deltay = (int) (mLastMotionY - y);      mLastMotionY = y;      if (isButtom(deltay)) {       setVerticalScrollBarEnabled(false);       scrollBy(0, deltay);       return true;      }      if (isHeader(deltay)) {       setVerticalScrollBarEnabled(false);       scrollBy(0, deltay);       return true;      }      break;     case MotionEvent.ACTION_UP:      mLastMotionY = 0;      if (getScrollY()!=0) {       mScroller.startScroll(0, getScrollY(), 0, -getScrollY(), 1000);       invalidate();       handler.sendEmptyMessageDelayed(0, 500);       return true;      }      break;     default:      break;     }     return super.dispatchTouchEvent(event);   }   private boolean isHeader(int deltay) {     int firstTop = getChildAt(0).getTop();     int effectivePaddingTop = getListPaddingTop();     int spaceAbove = effectivePaddingTop - firstTop;     return getFirstVisiblePosition() == 0&&spaceAbove<=0&&deltay<0;   }   private boolean isButtom(int deltay) {      int lastBottom = getChildAt(getChildCount() - 1).getBottom();      int effectivePaddingBottom = getListPaddingBottom();      return getLastVisiblePosition() == (getCount() - 1)&&lastBottom<=(getHeight()-effectivePaddingBottom)&&deltay>0;   }     Handler handler = new Handler(){     public void handleMessage(android.os.Message msg) {      int what = msg.what;      switch (what) {      case 0:       setVerticalScrollBarEnabled(true);       invalidate();       break;      default:       break;      }     };   };   }

下载地址