美文网首页
仿带有粘性的圆形刷新控件(2)

仿带有粘性的圆形刷新控件(2)

作者: clam314 | 来源:发表于2017-03-07 13:38 被阅读16次

实现效果:


上一篇写了关于图形相关绘制:
http://www.jianshu.com/p/25aa4789b3fd

关于动画方面,主要分两个方面:
一、圆圈拉伸的动画。
1 、圆被拉出去时的动画
2、圆拉伸后缩回去的动画
二、在加载时中心圆弧的动画

1、圆被拉伸出去时的动画

首先是记录下手指按下的点的坐标downPoint,然后是手指滑动后停留的点movePoint。并调用invalidate()让view根据两点的状态重新绘制。这样就实现圆随手指滑动而拉伸的动画
并且在此判断滑动的距离是否触发回滚动画

            case MotionEvent.ACTION_DOWN:
                if(!stickyAnimator.isRunning() && !loadAnimator.isRunning()){
                    downPoint.x = x;
                    downPoint.y = y;
                    movePoint.set(downPoint);
                    resetLoadAnimator();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(!stickyAnimator.isRunning() && !loadAnimator.isRunning() && !loading){
                    movePoint.x = x;
                    movePoint.y = y;
                    float distanceMove = getDistanceBetweenTwoPoints(downPoint.x,downPoint.y,movePoint.x,movePoint.y);
                    //滑动距离在动作范围内,则开始执行回滚动画和loading动画
                    if(inLoadArea(distanceMove)){
                        loading = true;
                        executeAnimator(distanceMove);
                    }
                    invalidate();
                }
                break;

2、圆形缩回的动画
除了在手指滑动距离超过一定范围后触发,在手指离开屏幕时也会触发

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if(!stickyAnimator.isRunning() && !loadAnimator.isRunning() && !loading){
                    movePoint.x = x;
                    movePoint.y = y;
                    float distanceUp = getDistanceBetweenTwoPoints(downPoint.x,downPoint.y,movePoint.x,movePoint.y);
                    //滑动距离在动作范围内,则开始执行回滚动画和loading动画,否则只开始回滚动画
                    if(inLoadArea(distanceUp)){
                       loading = true;
                    }
                    executeAnimator(distanceUp);
                }
                break;

回滚的动画,其实就是手指最后离开的点movePoint沿着直线移动到当初按下的点downPoin的过程。就是movePoint和downPoin两点的距离distance逐渐变为0的过程,根据distance的变化,可以计算回来movePoint的变化的一系列坐标。按上一篇的介绍,图形的绘制会根据downPoint和movePoint的值来绘制,这样每次movePoint得到新值后,重新绘制就可以实现动画
初始化的时候就可以设置好动画的参数,StickyAnimator就是负责执行缩回动画的

        //这里先不给animator设置evaluator,因为暂时还不知道需要变化的值,此时设置了也无效
        evaluator = new FloatEvaluator();
        stickyAnimator = new ValueAnimator();
        //设置插值器
        stickyAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        //设置属性值变化的监听,这里得到的newDistance就是两点新的距离
        stickyAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float newDistance = (float) animation.getAnimatedValue();
                float distance = getDistanceBetweenTwoPoints(downPoint.x,downPoint.y,movePoint.x,movePoint.y);
                float cos = (movePoint.x - downPoint.x)/distance;
                float sin = (movePoint.y - downPoint.y)/distance;
                movePoint.x = downPoint.x + newDistance * cos;
                movePoint.y = downPoint.y + newDistance * sin;
                invalidate();
            }
        });
        //圆形缩回来后判断是否需要执行loading动画
        stickyAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //在onTouchEvent里面判断了移动的距离是否触发加载动画
                if(loading){
                    loadAnimator.start();
                    if(mReloadListener != null) mReloadListener.onReload();
                }
            }
        });

在onTouchEvent()方法里面判断执行的时机,并且获取动画需要变化的值

private boolean inLoadArea(float distance){
        return distance <= MaxMoveDistance*0.75 && distance >= MaxMoveDistance * 0.33;
    }
private void executeAnimator(float distance){
        //两个圆重合时无需回滚
        if(distance == 0) return;
        stickyAnimator.setObjectValues(distance,0);
        stickyAnimator.setEvaluator(evaluator);
        stickyAnimator.setDuration(STICKY_DURATION);
        stickyAnimator.start();
    }

3、加载动画的实现
触发加载动画后,mLoadAnimatorValue的值由0到1,然后再绘制的时候根据这个值计算出截取圆弧的部分

        loadAnimator = ValueAnimator.ofFloat(0,1).setDuration(LOADING_DURATION);
        loadAnimator.setRepeatCount(-1);//loading动画一直执行,直到调用cancel()后才停止
        loadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mLoadAnimatorValue = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
    private void drawLoading(Canvas canvas){
        //基本和绘制一般状态的时候一样,除了截取的起点和终点需要动态的计算
        canvas.save();
        canvas.translate(circleStart.centerPoint.x, circleStart.centerPoint.y);
        canvas.scale(1 - mScale,1 - mScale);
        pathMeasure.setPath(mLoadPath,false);
        Path newPath = new Path();
        float stop = pathMeasure.getLength() * mLoadAnimatorValue;
        float start = (float)(stop - (0.5 - Math.abs(mLoadAnimatorValue - 0.5)) * 200f);
        pathMeasure.getSegment(start,stop,newPath,true);
        canvas.drawPath(newPath, mLoadPaint);
        canvas.restore();
    }

当loading动画会一直执行直到调用cancel()方法才停止。当所有动画都停止后,在手指按下屏幕的时候,重置一下状态

            case MotionEvent.ACTION_DOWN:
                if(!stickyAnimator.isRunning() && !loadAnimator.isRunning()){
                    downPoint.x = x;
                    downPoint.y = y;
                    movePoint.set(downPoint);
                    resetLoadAnimator();
                }
                break;

项目地址:https://github.com/clam314/StickyCircleView

相关文章

网友评论

      本文标题:仿带有粘性的圆形刷新控件(2)

      本文链接:https://www.haomeiwen.com/subject/hnxmgttx.html