弹性ScrollView-仿微信弹性页面

标签: 弹性ScrollView

一、先看效果

stretchScrollView.gif

二、准备工作

要实现这个效果,我的想法是给ScrollView包一个container,然后判断边界值,看当前的touch事件交给谁去处理。回弹的效果交给Scroller处理,甚至可以写出一个下拉刷新,看代码分析吧。

三、代码分析

在dispatchTouchEvent中去判断边界值,dispatchTouchEvent返回true或者false都是自己消费当前事件,否则super传递下去。代码如下:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        float currentY = ev.getY();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastY = currentY;
                break;
            case MotionEvent.ACTION_MOVE:
                float distanceY = currentY - mLastY;
                if (mIsDraging) {
                    if (distanceY <= 0) {
                        if(mScrollView.isScrolledToTop()) {
                            scrollTo(0, 0);
                            mIsDraging = false;
                            return super.dispatchTouchEvent(ev);
                        }
                    }else{
                        if(mScrollView.isScrolledToBottom()){
                            scrollTo(0, 0);
                            mIsDraging = false;
                            return super.dispatchTouchEvent(ev);
                        }
                    }
                    scrollTo(0, (int) (-distanceY * ratio));
                    return true;
                } else {
                    if (Math.abs(distanceY) > mTouchSlop) {
                        if (distanceY > 0) {  // 向下
                            if (mScrollView.isScrolledToTop()) {
                                mLastY = currentY;
                                mIsDraging = true;
                            }
                        }else{
                            if(mScrollView.isScrolledToBottom()){
                                mLastY = currentY;
                                mIsDraging = true;
                            }
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mIsDraging) {
                    int scrollY = getScrollY();
                    mScroller.startScroll(0, scrollY, 0, -scrollY, duration);
                    mIsDraging = false;
                    invalidate();
                    return true;
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
  1. 首先DOWN下记录起始位置,MOVE下先判断当前是不是拖拽状态mIsDraing,否,进入else里面,如果手指滑动距离需要响应了,判断方向,如果向下,还要看ScrollView是不是在顶部(为什么?),如果在顶部,那么记录当前 y 坐标(因为在判断这个期间,手指已经向下滑了一段距离了,如果还记录之前的位置,会很突兀),并将拖拽mIsDraing = true,开始向下。
  2. 这个时候再进入MOVE,已经是拖拽中,这个时候可以直接调用
scrollTo(0, (int) (-distanceY * ratio));
return true;

ratio是弹性系数。但是考虑到一种情况就是,刚开始下滑的时候手指突然向上滑动,这个时候container到顶了,ScrollView也在顶部,这个时候事件需要交给ScrollView而不是container继续滑动。同样的道理在底部回弹的时候,也存在上拉container到底了这个时候手指向下滑动,同样需要把事件交给ScrollView处理。所以在scrollTo之前需要再一次判断distanceY,如果小于0并且ScrollView在底部,事件传递,container需要恢复开始位置,这个时候虽然手指没有抬起,但是也不能是拖拽状态:

                            scrollTo(0, 0);
                            mIsDraging = false;
                            return super.dispatchTouchEvent(ev);
  1. ScrollView需要能判断有没有到顶或到底,重写一个StretchScrollView:
@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (getScrollY() == 0) {
            isScrolledToTop = true;
            isScrolledToBottom = false;
        } else if (getScrollY() + getHeight() - getPaddingTop()-getPaddingBottom() == getChildAt(0).getHeight()) {
            isScrolledToTop = false;
            isScrolledToBottom = true;
        } else {
            isScrolledToTop = false;
            isScrolledToBottom = false;
        }
    }

很简单对吧,同样适用于ListView,区别仅仅在于判断顶部底部的方法不一样。最后,可以扩展一点,凡是可以判断是顶部底部的view都可以加进来,抽象一个StretchView出来。附上gayHub地址。有兴趣拓展吧!

版权声明:本文为jimbo_xiaohei原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jimbo_xiaohei/article/details/80177107

智能推荐

idea基础–(7)–jsp页面Controller路径自动识别的问题“Cannot resolve controller URL ...”,Cannot resolve variable

idea之所以强大,就是强大的代码提示和联想功能,写起代码来简直不要太爽。但是这几天我发现在我的jsp页面中访问controller路径的时候不会自动提示了,对于这么严谨的我肯定要找出原因啊,哈哈。 最终效果:按住ctrl,同时点击左键会自动跳转到对应的controller代码块,爽。 需要同时满足的条件 JSP页面顶部包含如下代码: 在idea的项目设置中显示如下:  若显示的是spring a...

26_Python基础_继承

面向对象三大特性: 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 继承 实现代码的重用, 相同的代码不需要重复的编写 多态 不同的对象调用相同的方法,  产生不同的执行结果,  增加代码的灵活度 1.  单继承 1.1 概念 继承的概念:&...

循环

与任何程序设计语言一样Java利用条件语句与循环结构确定流程控制,一下总结一下Java中的循环语句: while do while for switch 对于golang来说: switch非常灵活。从第一个expr为true的case开始执行,如果case带有fallthrough,程序会继续执行下一条case,不会再判断下一条case的expr,如果之后的case都有fallthrough,d...

1638 统计只差一个字符的子串数目(动态规划)

1. 问题描述: 给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换一个不同字符以后,是 t 串的子串。换言之,请你找到 s 和 t 串中恰好只有一个字符不同的子字符串对的数目。比方说, "computer" 和 "computation"...

websocket基本原理

HTTP中一个request只能有一个response。而且这个response也是被动的,不能主动发起 因此过去的服务端推送信息是通过客户端不停的轮询实现的 websocket是双向通信协议,提供了服务端主动推送信息的能力 需要客户端(浏览器)和服务端同时支持 如果经过代理的话,还需要代理支持,否则有些代理在长时间无通信时会自动切断连接 因此WS为了保证连接不被断掉,会发心跳 WebSocket...

猜你喜欢

mybatis+ehcache二级缓存

导入jar包 mapper.xml文件开启二级缓存 pojo类实现序列化接口 配置ehcache.xml 测试...

python+opencv实现图像拼接

任务 拍摄两张图片去除相同部分,拼接在一起 原图 结果 步骤 读取两张图片 使用sift检测关键点及描述因子 匹配关键点 处理并保存关键点 得到变换矩阵 图像变换并拼接 代码实现 扩展 这里对右边图像进行变换,右边变得模糊,可以修改代码对左边图像变换 这里只有两张图片拼接,可以封装实现多张图片拼接 可以修改代码实现上下图片的拼接...

python_sklearn机器学习算法系列之AdaBoost------人脸识别(PCA,决策树)

          注:在读本文之前建议读一下之前的一片文章python_sklearn机器学习算法系列之PCA(主成分分析)------人脸识别(k-NearestNeighbor,KNN)         本文主要目的是通过一个简单的小...

memmove函数与memcpy函数的模拟实现

memmove函数和memcpy函数都是在内存复制任意类型的,但是它俩也有区别。当源区域和目标区域有重复的,memmove函数会复制缓冲区重叠的部分,而memcpy相反,会报出未知错误。 下面给出两个函数的实现 首先,memmove函数。 实现的基本原理如下图。 具体代码如下: memcpy函数的实现很简单,就直接给出源代码了...