带有滚动监听的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。

使用方法

与ScrollView使用基本一致

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) {
            //滑动位置改变
        }
    });

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值