帶有滾動監聽的ScrollView

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);
	}
}


ListenedScrollView

一個帶有監聽的ScrollView。html

使用方法

與ScrollView使用基本一致java

XML中

    <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) {
            //滑動位置改變
        }
    });
相關文章
相關標籤/搜索