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

写一个垃圾桶开关盖子的动画其实很简单

$
0
0

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

上周5因为要出去玩所以礼拜4基本没干活然后写了个垃圾桶的demo觉得蛮好玩的,准备做的深一点,但是文章还是一篇一篇发,省的有些小伙伴搞不清楚实现

还是先安利,地址如下:https://github.com/ddwhan0123/Useful-Open-Source-Android 最近把Rx和下拉刷新做了细分,方便大家查”裤”

先看下运行效果

这里写图片描述

就是一个垃圾桶然后用户点击按钮之后 盖子盖上去(可以用到项目里那种拖动到垃圾桶删除的效果)


首先讲下实现思路

首先我在https://icomoon.io/app/#/select里找了个垃圾桶的icon然后照着那个样子考虑我该怎么画(这网站还是不错的,不过现在都用iconfont了吧?)

因为 垃圾桶的桶身部分是不需要动画的,所以就先画桶身再画桶盖,桶盖用ValueAnimator解决旋转问题就好了


知识点

要画自定义控件,首先要知道view的绘画流程,具体理论知识就不说了以前说过,这里再点下
要自定义View 你要先实现onMeasure再是onDraw

onMeasure决定尺寸 onDraw决定具体ui展现

如果你是viewgroup的话还需要再实现onLayout来操作子视图间的位置关系


安卓的坐标系,跟我们数学的数轴不太一样,数轴有4个象限,而安卓只有一个。

屏幕左上角为(0,0)点,那右下角必然是最大点了。

越向右 x越大,越向下y越大。

ok,简单的道理讲完了,就开始贴代码看吧


代码实现

public class GabageCan extends View {

    private Paint paint;
    private Path path;
    private int viewWidth, viewHeight, picWidth, picHeight;
    private Float canBAnimProgress;
    private ValueAnimator animator;


    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(2000);
        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);
        Log.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;
    }
}

整体实现不难,只是提供个思路吧,写着玩,哈哈哈哈

源码地址:https://github.com/ddwhan0123/BlogSample/blob/master/GabageCan.class

之后可能写个拽入垃圾桶的动画,到时候再说吧。。。

作者:ddwhan0123 发表于2016/12/19 17:57:04 原文链接
阅读:381 评论:1 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles