项目需求:文章预览页滑动时隐藏浮动按钮,停止滑动时再显示出来。
博主文章预览页结构比较复杂,是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);
}
原理是在滑动事件里通过延迟判断是否停止滑动,联合是否正在触摸,一起判断用户是否已停止滑动操作