NestedScrollView滑动状态监听

826 阅读1分钟

项目需求:文章预览页滑动时隐藏浮动按钮,停止滑动时再显示出来。

博主文章预览页结构比较复杂,是NestedScrollView里面嵌套WebView和两个RecyclerView,如果仅是ScrollView或RecyclerView,监听滑动状态改变比较容易,但NestedScrollView本身不带滑动状态改变的监听。
几经百度没有找到合适方案,于是自己动手搞了一下。

import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;

public class ScrollListenNestedScrollView extends NestedScrollView {
    private static final String TAG = "ScrollListenNestedScrollView";

    private OnScrollListener onScrollListener;

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    public ScrollListenNestedScrollView(@NonNull Context context) {
        super(context);
    }

    public ScrollListenNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ScrollListenNestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private boolean isTouching;

    private boolean isScrolling;


    public static final int SCROLL_STATE_IDLE = 0;

    public static final int SCROLL_STATE_DRAGGING = 1;

    public static final int SCROLL_STATE_SETTLING = 2;

    private int state;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isTouching = true;
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                isTouching = false;
                checkDispatchScrollStopEvent();
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    private void checkDispatchScrollStopEvent() {
        if (!isScrolling && !isTouching) {
            int newState = SCROLL_STATE_IDLE;
            if (state != newState) {
                state = newState;
                if (onScrollListener != null) {
                    onScrollListener.onScrollStateChanged(this, state);
                }
            }
        }
    }


    private Handler handler = new Handler(Looper.getMainLooper());

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        isScrolling = true;
        int newState;
        if (isTouching) {
            newState = SCROLL_STATE_DRAGGING;
        } else {
            newState = SCROLL_STATE_SETTLING;
        }
        if (state != newState) {
            state = newState;
            if (onScrollListener != null) {
                onScrollListener.onScrollStateChanged(this, state);
            }
        }
        handler.removeCallbacksAndMessages(null);
        handler.postDelayed(() -> {
            isScrolling = false;
            checkDispatchScrollStopEvent();
        }, 100);


    }

    public interface OnScrollListener {

        void onScrollStateChanged(@NonNull ScrollListenNestedScrollView scrollView, int newState);

    }

原理是在滑动事件里通过延迟判断是否停止滑动,联合是否正在触摸,一起判断用户是否已停止滑动操作