关闭

Android上仿IOS弹性ScrollView

标签: android自定义View伸缩回弹效果
335人阅读 评论(0) 收藏 举报
分类:

这里写代码片#Android上仿IOS弹性ScrollView

滑动的原理:由于在ACTION_MOVE事件中不断获取手指移动的微小的偏移量,这样就将一段距离划分成了N个非常小的偏移量。虽然在每个偏移量里面,通过scrollBy方法进行了瞬间移动,但在整体上却可以获得一个平滑移动效果。

阻尼效果的实现原理:比如你下拉50dp,innerView只移动25dp。从效果上看就好像有个力在阻挠你下拉。

难点:
1. 移动过程中的处理:

MotionEvent.ACTION_MOVE中,在手指移动过程中,ev.getY()会不断获取当前手指的y坐标。

通过不断的计算前一次y的坐标和现在y坐标的偏移量detailY,然后把detailY在传到innerView.layout中,从而实现了下拉的效果。

2.Rect normal = new Rect()的作用?

用于记录innerView的原始位置。具体逻辑:在MotionEvent.ACTION_MOVE中判断normal为空,把innerView的四个点存起来。然后在MotionEvent.ACTION_UP中,即让innerView弹回原位的动画结束后,为innerView提供原始位置,并令normal再次为空。

3.isNeedMove()方法

作用:判断是否触发弹性移动效果

innerView.getMeasuredHeight():获取的是控件的总高度

getHeight():获取的是屏幕的高度

当控件的高度<屏幕的高度时候,getScrollY始终为0.
当控件的高度>屏幕的高度时候,上下滑动innerView时,getScrollY才会有变化的值。

针对第一种情况。只要scrollY == 0就会触发效果。
第二种情况。下拉的触发效果的条件scrollY == 0,上拉触发效果的条件是scrollY == offset

    private boolean isNeedMove() {
        int offset = innerView.getMeasuredHeight() - getHeight();
        int scrollY = getScrollY();
        // 0是顶部,后面那个是底部
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }

代码:

import android.content.Context;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.TranslateAnimation;
    import android.widget.ScrollView;

    /**
     * Created by Administrator on 2015/12/13.
     */
    public class MyScrollview extends ScrollView {

        //要操作的布局 孩子View
        private View innerView;
        // 点击时y坐标
        private float y;
        // 矩形(用于保存原innerView的四点坐标.)
        private Rect normal = new Rect();
        //用于记录动画是否结束
        private boolean animationFinish = true;

        public MyScrollview(Context context) {
            super(context, null);
        }

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

        public MyScrollview(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
        /***
         * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆* 盖了 onFinishInflate 方法,也应该调用父类的方法,使该方法得以执行.
         */
        @Override
        protected void onFinishInflate() {
            int childCount = getChildCount();
            if (childCount > 0) {
                innerView = getChildAt(0);
            }
        }
        // 首先要保存父类ScrollView的onTouchEvent事件,在这基础上加入回弹的逻辑
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if (innerView == null) {
                return super.onTouchEvent(ev);
            } else {
                commonTouchEvent(ev);
            }
            return super.onTouchEvent(ev);
        }

        /**
         * 自定义touch事件处理
         *
         * @param ev
         */
        private void commonTouchEvent(MotionEvent ev) {
            if (animationFinish) {
                switch (ev.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        y = ev.getY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float preY = y;
                        float nowY = ev.getY();
                        int detailY = (int) (preY - nowY);
                        y = nowY;
                        //操作view进行拖动detailY的一半
                        if (isNeedMove()) {
                            //布局改变位置之前,记录一下正常状态的位置
                            if (normal.isEmpty()) {
                                normal.set(innerView.getLeft(), innerView.getTop(), innerView.getRight(), innerView.getBottom());
                            }
                            innerView.layout(innerView.getLeft(), innerView.getTop() - detailY / 2, innerView.getRight(), innerView.getBottom() - detailY / 2);
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        y = 0;
                        //手指松开 布局回滚到原来的位置.
                        if (isNeedAnimation()) {
                            animation();
                        }
                        break;
                }
            }
        }

        private void animation() {
            // 开启移动动画
            TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - innerView.getTop());
            ta.setDuration(200);
            ta.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    animationFinish = false;
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    innerView.clearAnimation();
                    // 设置回到正常的布局位置
                    innerView.layout(normal.left, normal.top, normal.right, normal.bottom);
                    normal.setEmpty();
                    animationFinish = true;
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });
            innerView.startAnimation(ta);
        }

        /**
         * 判断是否需要回滚 是否需要开启动画
         *
         * @return
         */
        private boolean isNeedAnimation() {
            return !normal.isEmpty();
        }

        /**
         * 判断是否需要移动 innerView.getMeasuredHeight():获取的是控件的总高度
         * getHeight():获取的是屏幕的高度
         * @return
         */
        private boolean isNeedMove() {
            int offset = innerView.getMeasuredHeight() - getHeight();
            int scrollY = getScrollY();
            // 0是顶部,后面那个是底部
            if (scrollY == 0 || scrollY == offset) {
                return true;
            }
            return false;
        }
    }
1
0
查看评论

Android 之实现仿IOS弹性ScrollView

import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.V...
  • jky_yihuangxing
  • jky_yihuangxing
  • 2016-07-21 13:08
  • 502

Android上实现仿IOS弹性ScrollView

前言 IOS的UI和用户体验是它的优势, 与IOS相比, Android的UI和用户体验可能要差一些。 虽然Android版本已经到了4.4, 对系统的各个方法进行了大量实质性的优化, 但他的显示效果和交互体验依然不及IOS。 例如IOS上的很多控件都是带弹性的, 也就是用于拖拽一个控件到了该控...
  • brave2211
  • brave2211
  • 2014-02-17 09:59
  • 13740

Android仿IOS上拉/下拉弹性效果ScrollView

效果图如下: 实现原理: Android自带的ScrollView滑动到顶部和底部后,就不能继续拖动了,因此要实现IOS的拉动弹性效果,可以自定义一个布局,继承ScrollView。 在最顶部时,可以向下拉动,并且弹回。 在最底部时,可以向上拉动,并且弹回。 不在最底部和最顶部时,就是默认的Sc...
  • tangletao
  • tangletao
  • 2016-12-04 21:47
  • 684

Android仿IOS上拉下拉弹性效果

用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好;Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果。先看效果,感觉有些时候还是蛮实用的。     思路:其实原理很简单,实现一个自定义的Scrollv...
  • u014733374
  • u014733374
  • 2015-01-15 11:52
  • 3378

android 弹性ScrollView(已优化)

想要的效果最近项目中想实现一个效果,效果如下: 网上demo展示就是上滑或者下滑,能实现弹性效果,代码大致如下:public class BounceScrollView extends ScrollView { private View inner;// 孩子View priv...
  • a394268045
  • a394268045
  • 2016-07-12 19:52
  • 9947

Android自定义view-弹性ScrollView(上)

前言: 相信很多安卓开发者都很头痛的一件事就是公司要求做的app和IOS端的风格保持一致,很多IOS端中具有弹性的ScrollView在android开发中不失为一个难题(相应的效果见IOS的微信端等等...)对应的软件可以查看。为了实现这样的效果,毫无疑问的一件事:可以考虑重写我们的ScrollV...
  • SmartIceberg
  • SmartIceberg
  • 2016-02-22 16:04
  • 1258

android 仿ios带弹簧效果的ScrollView

仿ios弹簧效果
  • sunxiaogang0214
  • sunxiaogang0214
  • 2016-08-26 17:49
  • 1651

Android自定义view-弹性ScrollView(下)

前言: 继上篇博客Android自定义view-弹性ScrollView(上)介绍的一种实现弹性ScrollView的方法后,有没有觉得处理touch事件太过于麻烦了好吧,我也觉得麻烦,决定就用现在比较火的ViewDragHelper去实现事件的控制。这篇博文的重点不在于ViewDragHelper...
  • SmartIceberg
  • SmartIceberg
  • 2016-02-22 17:05
  • 1291

Android自定义控件(二)——有弹性的ScrollView

此控件实现了自定义的ScrollView, 此ScrollView当手指滑动到ScrollView的顶部、底部时, 可以继续的向上、向下拉伸。当释放手指的时候,向上、下弹回。 效果如图所示: 主要代码: public class ElasticScrollView extends ScrollV...
  • a105865708
  • a105865708
  • 2014-01-03 10:10
  • 4049

仿IOS弹性ScrollView

仿IOS弹性ScrollView http://www.apkbus.com/android-83674-1-1.html ScrollView反弹效果的实现 http://www.eoeandroid.com/forum.php?mod=viewthread&tid=1009...
  • song_shi_chao
  • song_shi_chao
  • 2013-03-18 17:44
  • 1165
    个人资料
    • 访问:5089次
    • 积分:178
    • 等级:
    • 排名:千里之外
    • 原创:13篇
    • 转载:3篇
    • 译文:0篇
    • 评论:1条
    文章分类
    文章存档
    最新评论