ScrollView和WebView滑动的距离

ScrollView的时候:

使用场景:

1. 做一些复杂动画的时候,需要动态判断当前的ScrollView是否滚动到底部或者顶部

2. ScrollView滚动到顶部或者底部时主动触发一些操作(典型的就是滚动到底部触发自动加载操作)

 

两种方式:

1. onScrollChanged方式,自己计算

2. onOverScrolled使用系统计算的结果,api >= 9才支持

可能忽视的细节1:

如果是手势滑动,上面两种方式都对,但是如果是调用ScrollViewsmoothScrollToscrollTo方法来滚动的话,

只有onScrollChanged监听对,onOverScrolled监听不对,因为通过代码来滚动话是精确滚动,onOverScrolled方法没处理这种情况

 

两种方式如何选择?

一般来说如果系统有实现的东西,就用系统的,我们毕竟是基于Android系统来做开发,别人做的考虑很多适配兼容问题

所以原则就是系统有就用它的,没有才用我们自己的,具体实现仔细看代码,记得看注释

如果不考虑smoothScrollTo和scrollTo滚动,上面这个原则就是对的,如果要考虑的话,这里只能使用onScrollChanged

 

滚动到顶部和底部时对应的计算关系:

 

 

备注:无padding的情况可以转换为有padding的情况,即tp,bp=0

mScrollY + H – tp – bp = h ===> mScrollY + H = h 

 

代码实现,自定义View,可以直接拷贝就可以使用

 

public class CalculateHeightScrollView extends ScrollView {
    private boolean isScrolledToTop = true; // 初始化的时候设置一下值
    private boolean isScrolledToBottom = false;
    int percentRate = 0; //计算百分比用


    public CalculateHeightScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private ISmartScrollChangedListener mSmartScrollChangedListener;

    /**
     * 定义监听接口
     */
    public interface ISmartScrollChangedListener {
        void onScrolledToBottom();

        void onScrolledToTop();

        void getScrollPercentRate(int percentRate);
    }

    public void setScanScrollChangedListener(ISmartScrollChangedListener smartScrollChangedListener) {
        mSmartScrollChangedListener = smartScrollChangedListener;
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        if (scrollY == 0) {
            isScrolledToTop = clampedY;
            isScrolledToBottom = false;
            percentRate = 0;
        } else {
            isScrolledToTop = false;
            isScrolledToBottom = clampedY;
            percentRate = (scrollY + getHeight() - getPaddingTop() - getPaddingBottom()) * 100 / getChildAt(0).getHeight();
        }
        notifyScrollChangedListeners();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);

        if (android.os.Build.VERSION.SDK_INT < 9) {
            if (getScrollY() == 0) {    // 小心踩坑1: 这里不能是getScrollY() <= 0
                isScrolledToTop = true;
                isScrolledToBottom = false;
                percentRate = 0;
            } else if (getScrollY() + getHeight() - getPaddingTop() - getPaddingBottom() == getChildAt(0).getHeight()) {
                // 小心踩坑2: 这里不能是 >=
                // 小心踩坑3(可能忽视的细节2):这里最容易忽视的就是ScrollView上下的padding 
                isScrolledToBottom = true;
                isScrolledToTop = false;
                percentRate = (getScrollY() + getHeight() - getPaddingTop() - getPaddingBottom()) * 100 / getChildAt(0).getHeight();
            } else {
                isScrolledToTop = false;
                isScrolledToBottom = false;
                percentRate = (getScrollY() + getHeight() - getPaddingTop() - getPaddingBottom()) * 100 / getChildAt(0).getHeight();
            }
            notifyScrollChangedListeners();
        }
        // 有时候写代码习惯了,为了兼容一些边界奇葩情况,上面的代码就会写成<=,>=的情况,结果就出bug了
        // 我写的时候写成这样:getScrollY() + getHeight() >= getChildAt(0).getHeight()
        // 结果发现快滑动到底部但是还没到时,会发现上面的条件成立了,导致判断错误
        // 原因:getScrollY()值不是绝对靠谱的,它会超过边界值,但是它自己会恢复正确,导致上面的计算条件不成立
        // 仔细想想也感觉想得通,系统的ScrollView在处理滚动的时候动态计算那个scrollY的时候也会出现超过边界再修正的情况
    }

    private void notifyScrollChangedListeners() {
        if (isScrolledToTop) {
            if (mSmartScrollChangedListener != null) {
                mSmartScrollChangedListener.onScrolledToTop();
            }
        } else if (isScrolledToBottom) {
            if (mSmartScrollChangedListener != null) {
                mSmartScrollChangedListener.onScrolledToBottom();
            }
        }

        if (mSmartScrollChangedListener != null) {
            mSmartScrollChangedListener.getScrollPercentRate(percentRate);
        }
    }

    public boolean isScrolledToTop() {
        return isScrolledToTop;
    }

    public boolean isScrolledToBottom() {
        return isScrolledToBottom;
    }


}

WebView的时候:

public class ScrollWebView extends WebView {
        public OnScrollChangeListener listener;
 
        public ScrollWebView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
 
        public ScrollWebView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
 
        public ScrollWebView(Context context) {
            super(context);
        }
 
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
 
            super.onScrollChanged(l, t, oldl, oldt);
 
            float webcontent = getContentHeight() * getScale();// webview的高度
            float webnow = getHeight() + getScrollY();// 当前webview的高度
            Log.i("TAG1", "webview.getScrollY()====>>" + getScrollY());
            if (Math.abs(webcontent - webnow) < 1) {
                // 已经处于底端
                // Log.i("TAG1", "已经处于底端");
                listener.onPageEnd(l, t, oldl, oldt);
            } else if (getScrollY() == 0) {
                // Log.i("TAG1", "已经处于顶端");
                listener.onPageTop(l, t, oldl, oldt);
            } else {
                listener.onScrollChanged(l, t, oldl, oldt);
            }
 
        }
 
        public void setOnScrollChangeListener(OnScrollChangeListener listener) {
 
            this.listener = listener;
 
        }
 
        public interface OnScrollChangeListener {
            public void onPageEnd(int l, int t, int oldl, int oldt);
            public void onPageTop(int l, int t, int oldl, int oldt);
            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、付费专栏及课程。

余额充值