Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

写一个把控件丢到垃圾桶的动画其实很简单

$
0
0

转载请注明出处:王亟亟的大牛之路

上次写了个垃圾桶开盖打demo,然后说要再写一篇往垃圾桶丢垃圾的demo,延期了一礼拜今天终于逼着自己补完了。

还是老规矩,先安利:

https://github.com/ddwhan0123/Useful-Open-Source-Android

总有一款适合你!


这里写图片描述

效果就是把某个控件丢到垃圾桶里然后这控件就没了(好像有点丑,还是可以继续调的,这个你理解就好)


实现分析

垃圾桶的开关用的是ValueAnimator,而这次的连环拳是ObjectAnimator,ObjectAnimator我去年有些过,可以看:http://blog.csdn.net/ddwhan0123/article/details/50470237

试图的平移等效果都是相对平移,那么我们首先要获取被丢进垃圾桶的控件在activity内的实际坐标

 view.getLocationOnScreen(viewPoint);

得到在页面的(x,y)坐标
然后得到偏移量
x= (x-垃圾桶x)
y= (x-垃圾桶y)


代码

package wjj.com.garbagecandemo.customview;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.Keyframe;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;

import com.elvishew.xlog.XLog;

import wjj.com.garbagecandemo.R;


/**
 * Created by jiajiewang on 2016/12/15.
 */

public class GabageCan extends View {

    private Paint paint;
    private Path path;
    private int viewWidth, viewHeight, picWidth, picHeight;
    private int[] centerPoint;
    private int[] viewPoint;
    private Float canBAnimProgress;
    private ValueAnimator animator;
    private Rect globalRect;

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

    public GabageCan(Context context) {
        super(context);
        init();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(getResources().getColor(R.color.colorAccent));
        //设置画笔
        paint.setStrokeWidth(5f);
//        canvas.drawColor(Color.WHITE);
        //创建下半部分的路径和三条线
        createCanBPath();
        //画路径和线
        canvas.drawPath(path, paint);
        //动画判断是否刷新视图
        if (animator != null && animator.isRunning()) {
            //动画执行过程中具体帧值
            canBAnimProgress = (Float) animator.getAnimatedValue();
            drawCan(0, canvas);
            drawCan(1, canvas);
            drawCan(2, canvas);
            invalidate();
        } else if (animator != null && !animator.isRunning()) {
            drawCan(1, canvas);
            drawCan(2, canvas);
        }
    }

    public void startAnimator() {
        animator = ValueAnimator.ofFloat(1f, 0f);
        animator.setDuration(2500);
        animator.start();
        invalidate();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMySize(100, widthMeasureSpec);
        int height = getMySize(100, heightMeasureSpec);

        if (width < height) {
            height = width;
        } else {
            width = height;
        }

        setMeasuredDimension(width, height);
        XLog.d("--->width " + width + " height " + height);
        viewWidth = width > 0 ? width : 0;
        viewHeight = height > 0 ? height : 0;
        if (viewWidth > 0) {
            picWidth = viewWidth / 3;
        }
        if (viewHeight > 0) {
            picHeight = viewHeight / 3;
        }
    }

    //初始化画笔
    private void init() {
        paint = new Paint();
        path = new Path();
        paint.setStyle(Paint.Style.STROKE);
    }

    private void drawCan(int type, Canvas canvas) {
        switch (type) {
            case 0:
                canvas.rotate(canBAnimProgress * 30, viewWidth / 2 + (picHeight / 2), viewHeight / 2 - (picWidth / 2));
                break;
            case 1:
                canvas.drawLine(viewWidth / 2 - (picWidth / 2) - 20, viewHeight / 2 - (picWidth / 2) - (picHeight / 8),
                        viewWidth / 2 + (picHeight / 2) + 20, viewHeight / 2 - (picWidth / 2) - (picHeight / 8), paint);
                break;
            case 2:
                canvas.drawRect(viewWidth / 2 - (picWidth / 9), viewHeight / 2 - (picWidth / 2) - (picHeight / 4), viewWidth / 2 + (picHeight / 9),
                        viewHeight / 2 - (picHeight / 2) - (picHeight / 8), paint);
                break;
            case 3:
                break;
        }
    }


    private void createCanBPath() {
        if (path == null) {
            path = new Path();
        }
        //画轮廓
        path.moveTo(viewWidth / 2 - (picWidth / 2), viewHeight / 2 - (picWidth / 2));
        path.lineTo(viewWidth / 2 - (picWidth / 3), viewHeight / 2 + (picHeight / 2));
        path.lineTo(viewWidth / 2 + (picHeight / 3), viewHeight / 2 + (picHeight / 2));
        path.lineTo(viewWidth / 2 + (picHeight / 3), viewHeight / 2 + (picHeight / 2));
        path.lineTo(viewWidth / 2 + (picHeight / 2), viewHeight / 2 - (picWidth / 2));
        //画里面的竖线
        path.moveTo(viewWidth / 2 - (picWidth / 5), viewHeight / 2 - (picWidth / 3));
        path.lineTo(viewWidth / 2 - (picWidth / 5), viewHeight / 2 + (picHeight / 3));
        path.moveTo(viewWidth / 2 + (picWidth / 5), viewHeight / 2 - (picWidth / 3));
        path.lineTo(viewWidth / 2 + (picWidth / 5), viewHeight / 2 + (picHeight / 3));
        path.moveTo(viewWidth / 2, viewHeight / 2 - (picWidth / 3));
        path.lineTo(viewWidth / 2, viewHeight / 2 + (picHeight / 3));
    }


    private int getMySize(int defaultSize, int measureSpec) {
        int mySize = defaultSize;

        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);

        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
                mySize = defaultSize;
                break;
            }
            case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
                //我们将大小取最大值,你也可以取其他值
                mySize = size;
                break;
            }
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
                mySize = size;
                break;
            }
        }
        return mySize;
    }

    //获取控件中心
    public int[] getCenterPoint() {
        if (globalRect == null) {
            globalRect = new Rect();
        }
        if (centerPoint == null) {
            centerPoint = new int[2];
        }
        this.getLocationOnScreen(centerPoint);
        centerPoint[0] = centerPoint[0] + viewWidth / 2;
        centerPoint[1] = centerPoint[1] + viewHeight / 2;
        return centerPoint;
    }

    //丢垃圾丢动画
    public void throwAnim(final View view) {
        if (viewPoint != null) {
            viewPoint = null;
        }
        viewPoint = new int[2];
        view.getLocationOnScreen(viewPoint);
        //被丢的控件左上角位置
        XLog.d("--->viewPoint x: " + viewPoint[0] + " y: " + viewPoint[1]);
        //转着被丢进去
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f);
        //偏移x
        ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "translationX", 0.0f, centerPoint[0] - viewPoint[0] - viewWidth / 2);
        //偏移y
        ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "translationY", 0.0f, centerPoint[1] - viewPoint[1] - viewHeight / 4);
        //基本上控件都比垃圾桶大,所以做了个缩放
        ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 0.6f);
        ObjectAnimator objectAnimator5 = ObjectAnimator.ofFloat(view, "scaleY", 1.0f, 0.6f);
        AnimatorSet animationSet = new AnimatorSet();//组合动画
        animationSet.play(objectAnimator1).with(objectAnimator2).with(objectAnimator).with(objectAnimator4).with(objectAnimator5);
        animationSet.setDuration(800);
        animationSet.setInterpolator(new AccelerateInterpolator());
        animationSet.start();
        animationSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                //丢进去后做扭动获取用户视觉点然后隐藏表示被删了
                startShakeByPropertyAnim(view, 0.4f, 0.6f, 7.0f, 800);
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
    }

    private void startShakeByPropertyAnim(final View view, float scaleSmall, float scaleLarge, float shakeDegrees, long duration) {
        if (view == null) {
            return;
        }

        //先变小后变大
        PropertyValuesHolder scaleXValuesHolder = PropertyValuesHolder.ofKeyframe(View.SCALE_X,
                Keyframe.ofFloat(0f, 1.0f),
                Keyframe.ofFloat(0.25f, scaleSmall),
                Keyframe.ofFloat(0.5f, scaleLarge),
                Keyframe.ofFloat(0.75f, scaleLarge),
                Keyframe.ofFloat(1.0f, scaleLarge)
        );
        PropertyValuesHolder scaleYValuesHolder = PropertyValuesHolder.ofKeyframe(View.SCALE_Y,
                Keyframe.ofFloat(0f, 1.0f),
                Keyframe.ofFloat(0.25f, scaleSmall),
                Keyframe.ofFloat(0.5f, scaleLarge),
                Keyframe.ofFloat(0.75f, scaleLarge),
                Keyframe.ofFloat(1.0f, scaleLarge)
        );

        //先往左再往右
        PropertyValuesHolder rotateValuesHolder = PropertyValuesHolder.ofKeyframe(View.ROTATION,
                Keyframe.ofFloat(0f, 0f),
                Keyframe.ofFloat(0.1f, -shakeDegrees),
                Keyframe.ofFloat(0.2f, shakeDegrees),
                Keyframe.ofFloat(0.3f, -shakeDegrees),
                Keyframe.ofFloat(0.4f, shakeDegrees),
                Keyframe.ofFloat(0.5f, -shakeDegrees),
                Keyframe.ofFloat(0.6f, shakeDegrees),
                Keyframe.ofFloat(0.7f, -shakeDegrees),
                Keyframe.ofFloat(0.8f, shakeDegrees),
                Keyframe.ofFloat(0.9f, -shakeDegrees),
                Keyframe.ofFloat(1.0f, 0f)
        );

        ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, scaleXValuesHolder, scaleYValuesHolder, rotateValuesHolder);
        objectAnimator.setDuration(duration);
        objectAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                view.setVisibility(View.GONE);
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
        objectAnimator.start();
    }
}

总结:

整体实现不算复杂,你还可以给丢过去的过程做曲线优化,包括给垃圾桶的边界等做优化(这边主要是实现个demo)

例子例申请了一堆objectAnimator,这点不是太可取,实际场景下还是少开对象。

其他暂时没想到,有问题的可以联系我,微信如下
这里写图片描述

源码地址:https://github.com/ddwhan0123/BlogSample/tree/master/GarbageCan

部分动画代码来自于:https://github.com/zhenghuiy/ShakeAnimationDemo
感谢作者!

作者:ddwhan0123 发表于2016/12/23 16:30:39 原文链接
阅读:314 评论:1 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>