package com.util.ListenedScrollView; import android.content.Context; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.widget.ScrollView; /** * 帶有滾動監聽的ScrollView * * @author 拉風的道長(OSChina.net) * */ public class ListenedScrollView extends ScrollView { private static final String TAG = ListenedScrollView.class.getSimpleName(); // 檢查ScrollView的最終狀態 private static final int CHECK_STATE = 0; // 外部設置的監聽方法 private OnScrollListener onScrollListener; // 是否在觸摸狀態 private boolean inTouch = false; // 上次滑動的最後位置 private int lastT = 0; /** * 構造方法 * * @param context */ public ListenedScrollView(Context context) { super(context); } /** * 構造方法 * * @param context * @param attrs */ public ListenedScrollView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 構造方法 * * @param context * @param attrs * @param defStyleAttr */ public ListenedScrollView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: inTouch = true; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: inTouch = false; lastT = getScrollY(); checkStateHandler.removeMessages(CHECK_STATE);// 確保只在最後一次作這個check checkStateHandler.sendEmptyMessageDelayed(CHECK_STATE, 5);// 5毫秒檢查一下 break; default: break; } Log.d(TAG, "inTouch = " + inTouch); return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (onScrollListener == null) { return; } Log.d(TAG, "t = " + t + ", oldt = " + oldt); if (inTouch) { if (t != oldt) { // 有手指觸摸,而且位置有滾動 Log.i(TAG, "SCROLL_STATE_TOUCH_SCROLL"); onScrollListener.onScrollStateChanged(this, OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); } } else { if (t != oldt) { // 沒有手指觸摸,而且位置有滾動,就能夠簡單的認爲是在fling Log.w(TAG, "SCROLL_STATE_FLING"); onScrollListener.onScrollStateChanged(this, OnScrollListener.SCROLL_STATE_FLING); // 記住上次滑動的最後位置 lastT = t; checkStateHandler.removeMessages(CHECK_STATE);// 確保只在最後一次作這個check checkStateHandler.sendEmptyMessageDelayed(CHECK_STATE, 5);// 5毫秒檢查一下 } } onScrollListener.onScrollChanged(l, t, oldl, oldt); } private Handler checkStateHandler = new Handler() { @Override public void handleMessage(Message msg) { if (lastT == getScrollY()) { // 若是上次的位置和當前的位置相同,可認爲是在空閒狀態 Log.e(TAG, "SCROLL_STATE_IDLE"); onScrollListener.onScrollStateChanged(ListenedScrollView.this, OnScrollListener.SCROLL_STATE_IDLE); // from http://blog.chinaunix.net/uid-20782417-id-1645164.html if (getScrollY() + getHeight() >= computeVerticalScrollRange()) { onScrollListener.onBottomArrived(); } else { Log.d(TAG, "沒有到最下方"); } } } }; /** * 設置滾動監聽事件 * * @param onScrollListener * {@link OnScrollListener} 滾動監聽事件(注意類的不一樣,雖然名字相同) */ public void setOnScrollListener(OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; } /** * 滾動監聽事件 * * @author 拉風的道長 * */ 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; /** * 滑動到底部回調 */ public void onBottomArrived(); /** * 滑動狀態回調 * * @param view * 當前的scrollView * @param scrollState * 當前的狀態 */ public void onScrollStateChanged(ListenedScrollView view, int scrollState); /** * 滑動位置回調 * * @param l * @param t * @param oldl * @param oldt */ public void onScrollChanged(int l, int t, int oldl, int oldt); } }
一個帶有監聽的ScrollView。html
與ScrollView使用基本一致java
<com.util.ListenedScrollView android:id="@+id/listenedScrollView" android:layout_width="match_parent" android:layout_height="match_parent" ... />
ListenedScrollView listenedScrollView = (ListenedScrollView)findViewById(R.id.listenedScrollView); //設置監聽。 listenedScrollView.setOnScrollListener(new ListenScrollView.OnScrollListener() { @Override public void onBottomArrived() { //滑倒底部了 } @Override public void onScrollStateChanged(ScrollView view, int scrollState) { //滑動狀態改變 } @Override public void onScrollChanged(int l, int t, int oldl, int oldt) { //滑動位置改變 } });