`

ScrollView反弹效果实现[bug修正版]

 
阅读更多

View中也有scrollBy和scrollTo这两个方法,但是ScrollView对scrollTo进行重写  
    由于:public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }
    View:public void scrollTo(int x, int y) {
        if (mScrollX != x || mScrollY != y) {
            int oldX = mScrollX;
            int oldY = mScrollY;
            mScrollX = x;
            mScrollY = y;
            onScrollChanged(mScrollX, mScrollY, oldX, oldY);
            if (!awakenScrollBars()) {
                invalidate();
            }
        }
    }
    所以也就相当于scrollBy和scrollTo这两个方法都被重写了。重写的代码中加入校验,当你移动到最上面或者最下面的时候无法再向上移动或向下移动。这就导致了如果简单调用scrollTo无法实现继续移动。如果你还要继续移动的话mScrollY 就为0或者是你内部视图的测量高度-ScrollView的高度。scrollTo是移动到,scrollBy是移动了。如下图:
   
                所以内容向下移动,手指向上滑动,那这个deltaY 就为正,也就是mScrollY =mScrollY +deltaY ,mScrollY 变大直到移动到最下无法移动位置;反之mScrollY 变小直到为0移动到最上面为止。
                final float preY = y;
                float nowY = ev.getY();
                int deltaY = (int) (preY - nowY);
                // 滚动,deltaY 为移动的距离,如果要用scrollTo需要计算准确的位置,也就是先前的位置在加上现在移动了多少
                scrollBy(0, deltaY);
               基于这些就可以重写ScrollView的onTouchEvent并结合ScrollView的内部视图的layout()方法、TranslateAnimation()实现反弹效果。
ScrollView代码:
----------------------------------------------------------------------------------------------------------------------

public class MyScrollView extends ScrollView {
    private View inner;
    private static final int DEFAULT_POSITION = -1;
    private float y = DEFAULT_POSITION;
    private Rect normal = new Rect();
    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onFinishInflate() {
        if (getChildCount() > 0) {
            inner = getChildAt(0);
        }
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        System.out.println("onTouchEvent");
        if (inner == null) {
            return super.onTouchEvent(ev);
        } else {
            commOnTouchEvent(ev);
        }
        return super.onTouchEvent(ev);
    }
    public void commOnTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            y = ev.getY();
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (isNeedAnimation()) {
                animation();
            }
            y = DEFAULT_POSITION;
            break;
        case MotionEvent.ACTION_MOVE:
            final float nowY = ev.getY();
            float preY = y;
            if (isDefaultPosition(y)) {
                preY = nowY;
            }
            int deltaY = (int) (preY - nowY);
            // 滚动
            scrollBy(0, deltaY);
            y = nowY;
            // 当滚动到最上或者最下时就不会再滚动,这时移动布局
            if (isNeedMove()) {
                if (normal.isEmpty()) {
                    // 保存正常的布局位置
                    normal.set(inner.getLeft(), inner.getTop(),
                            inner.getRight(), inner.getBottom());
                }
                // 移动布局
                inner.layout(inner.getLeft(), inner.getTop() - deltaY,
                        inner.getRight(), inner.getBottom() - deltaY);
            }
            break;
        default:
            break;
        }
    }
    // 检查是否处于默认位置
    private boolean isDefaultPosition(float position) {
        return position == DEFAULT_POSITION;
    }
    // 开启动画移动
    public void animation() {
        TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
                normal.top);
        ta.setDuration(200);
        inner.startAnimation(ta);
        // 设置回到正常的布局位置
        inner.layout(normal.left, normal.top, normal.right, normal.bottom);
        normal.setEmpty();
    }
    // 是否需要开启动画
    public boolean isNeedAnimation() {
        return !normal.isEmpty();
    }
    // 是否需要移动布局
    public boolean isNeedMove() {
        int offset = inner.getMeasuredHeight() - getHeight();
        int scrollY = getScrollY();
        // 位置处于最上和最下
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }
}
已经对它再次修正,如果仍然有问题,请描述清楚问题email:f059074251@163.com
分享到:
评论
1 楼 ailggxk 2012-08-21  
不错不错, 辛苦了

相关推荐

    Android ScrollView反弹效果

    本文将深入探讨如何实现一个自定义的ScrollView,以添加上、下拉的反弹效果,从而提高用户的交互体验。 首先,我们需要了解ScrollView的基本用法。ScrollView是一个可以包含单个直接子视图的垂直滚动容器。这意味着...

    Android自定义ScrollView反弹效果

    下面将详细介绍如何在Android中实现自定义ScrollView的反弹效果。 首先,我们需要创建一个新的ScrollView子类,例如命名为`BounceScrollView`。在这个自定义视图中,我们需要重写一些关键方法以实现回弹效果。关键...

    ScrollView反弹效果

    然而,在许多应用中,为了提供更丰富的用户体验,开发者会希望实现一种“反弹”效果,即当用户尝试在边界处继续滚动时,ScrollView会有个小幅度的回弹动作,模拟真实物理世界的弹性效果。这个“ScrollView反弹效果”...

    scrollView实现回弹阻尼效果(无bug)

    在"scrollView实现回弹阻尼效果(无bug)"的项目中,开发者针对这个问题进行了优化,提供了一个经过实际测试的无bug解决方案。这个项目可能包含了自定义的ScrollView类,该类通过重写滚动相关的函数,实现了平滑且...

    android scrollView 拉到最低和最顶端 反弹效果

    当用户滚动到ScrollView的顶部或底部时,有时我们希望实现一个反弹效果,即滚动条会在到达边界后短暂地回弹,增加用户体验的流畅感。这个效果通常被称为“橡皮筋效果”或“弹簧效果”,在iOS中称为“弹性滚动”,在...

    scrollview的回弹效果

    在压缩包中的`zhy_bounceScrollView02`文件可能是实现回弹效果的一个示例代码,可能包含了如何设置ScrollView、调整内容偏移量以及实现回弹动画的详细步骤。通过研究这个示例,开发者可以更好地理解如何在实际项目中...

    RN ScrollView 实现轮播图效果

    通过研究这些代码,你可以更深入地理解如何在RN中使用ScrollView实现轮播图效果。记得结合实际项目需求进行适当的调整,例如添加图片加载库处理网络图片,或者增加手势识别以支持更多交互方式。

    安卓ScrollView分区域上下左右反弹

    通过以上步骤,我们就可以在Android应用中实现类似iOS的ScrollView反弹效果。这种自定义的ScrollView可以为用户提供更丰富的交互体验,增加应用的吸引力。需要注意的是,实现这种效果需要对Android的触摸事件处理和...

    scrollview 章节选择效果

    在实现章节选择效果时,我们可以将每个关卡视为一个节点,然后将这些节点添加到ScrollView中。ScrollView会处理用户的滑动操作,使内容平滑滚动,从而达到选关的效果。 以下是一些关键步骤来创建这样的效果: 1. *...

    Android,自定义ScrollView,实现过度滑动时回弹效果

    要实现回弹效果,我们需要创建一个新的自定义ScrollView类,继承自Android的ScrollView,并重写其滚动相关的函数。关键在于计算当前滑动的位置,判断是否超过边界,然后模拟出回弹的动画效果。以下是一些核心步骤: ...

    ScrollView的阻尼回弹效果实现(仿qq空间)

    在本文中,我们将深入探讨如何在ScrollView中实现这种仿QQ空间的阻尼回弹效果。 首先,我们需要理解阻尼回弹的基本原理。阻尼回弹效果是基于物理学中的弹性运动理论,模拟真实世界中的弹簧回弹行为。在数字世界里,...

    Android ScrollView实现反弹效果的实例

    以上就是实现Android ScrollView反弹效果的基本步骤。这个过程中,关键在于对触摸事件的处理和动画的实现。通过自定义ScrollView,我们可以精确控制滚动行为,从而提供更丰富的用户体验。需要注意的是,反弹效果的...

    让ScrollView头部的View实现伸缩动画效果

    而标题提到的"让ScrollView头部的View实现伸缩动画效果"是一种增强用户体验的设计,它使得ScrollView的顶部视图在滚动时能够产生动态的伸缩效果,为应用增添了一丝动态美感。 要实现这样的效果,通常需要自定义一个...

    android ScrollView 阻尼回弹效果 仿微信

    而“阻尼回弹”或“橡皮筋”效果则是指在ScrollView滚动到边界时,手指松开后,内容会像橡皮筋一样有一种自然的反弹效果,就像微信朋友圈那样,给人一种更加真实的交互体验。 实现这种效果的关键在于自定义一个...

    Unity实现ScrollView滑动吸附功能

    本文实例为大家分享了Unity实现ScrollView滑动吸附的具体代码,供大家参考,具体内容如下 最近在做一个展示模块的时候遇到了一个需要实现滑动窗口并且能固定吸附距离的需求,借助UGUI的ScrollView的API以及Dotween...

    ScrollView+TableView滑动分层效果

    要实现"ScrollView+TableView滑动分层效果",我们首先要将TableView作为ScrollView的子视图进行添加。这可以通过代码或者Interface Builder完成。然后,我们需要监听ScrollView的滚动事件,当用户上拉时,隐藏或缩小...

    ScrollView 瀑布流实现

    在Android开发中,要实现这种效果,通常需要自定义一个ScrollView。ScrollView是Android提供的一个可以滚动容器,它可以包含一个直接子视图,并允许用户在垂直方向上滚动内容。现在我们来详细探讨如何通过自定义...

    ScrollView实现下拉刷新

    提到的开源项目"PullToRefresh"是一个流行的Android库,专门用于实现下拉刷新效果。它的核心原理是监听`ScrollView`的滚动事件,当用户下拉到顶部时触发特定的动画和逻辑,如显示一个刷新指示器并执行数据加载操作。...

Global site tag (gtag.js) - Google Analytics