实现监听滚动状态、滚动页码、滚动到最底部的ScrollView/android
提出问题
最近项目业务上有这样一个需求,原生实现阅读交易协议长文本,要求显示页码,阅读完成才能高亮同意按钮。采用ScrollView + TextView的方案只能实现展示和滚动阅读,对于页码和是否滚动到最底部的需求,需要进行扩展实现。
分析问题
我们知道ScrollView最多只能包含一个直接孩子,而且自身也有滚动回调方法,所以我们可以在滚动回调方法中做文章。,
解决问题
先看效果图:
下面直接上代码:
自定义ScrollView:
package com.bg.blogcodeproject.widget.scroll;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;
/**
* @Desc: 带滚动监听的ScrollView:
* 监听实时滚动位置,
* 监听滚动状态变化、
* 监听滚动页码变化、
* 监听是否滚动到底部
* @Author:bg
* @Date: 2022/3/22 17:00
*/
public class ObservableScrollView extends NestedScrollView {
/**
* 每隔80毫秒检查一次滚动状态变化
*/
private static final int CHECK_SCROLL_DELAY_MILLIS = 80;
private static final int MSG_SCROLL = 2468;
private static final String TAG = "ObservableScrollView";
/**
* 当前是否为触摸状态
*/
private boolean mTouched = false;
/**
* 当前是否滚动到底部
*/
private boolean mScrolledEnd = false;
/**
* 当前页码
*/
private int mPage = 1;
/**
* 总页码
*/
private int mTotalPage = 0;
/**
* 判断是否滑动到下一页的比例,取值范围区间(0,1)
*/
private static final float NEXT_PAGE_RATIO = 0.5f;
/**
* 记录当前的滚动状态
*/
private ScrollState mScrollState = ScrollState.IDLE;
private OnScrollStateChangedListener mOnScrollStateChangedListener;
private OnScrolledEndChangedListener mOnScrolledEndChangedListener;
private OnScrollPageNumChangedListener mOnScrollPageNumChangedListener;
public ObservableScrollView(@NonNull Context context) {
this(context, null);
}
public ObservableScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ObservableScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 视图树布局完成时计算是否滚动到底的初始状态
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// 计算是否滚动到底部
computeScrolledEnd(ObservableScrollView.this.getScrollY());
// 计算总页数
computeTotalPage(