Canvas 详解

Canvas 详解

这节我们来看一下 Canvas 的相关知识,官方文档有详细的功能说明,这里我们简要了解一下几个常用的功能

绘制文本、几何图形、位图

接口功能
drawText绘制文本
drawLine绘制连线
drawPath根据给定的Path,绘制连线
drawPoint绘制点
drawBitmap绘制位图

位置形状变换

接口功能
translate平移
scale缩放
rotate旋转
skew倾斜
clipXXX切割,参数指定区域内可以继续绘制
clipOutXXX切割,参数指定区域内不可以绘制
setMatrix通过矩阵实现平移、缩放、旋转等操作

爆炸粒子效果

简单实现一个爆炸粒子效果,使用相关功能,先上效果图
在这里插入图片描述

最后附上相关代码

package com.wuba.demo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;

import java.util.ArrayList;

/**
 * Author silence.
 * Time:2019-08-13.
 * Desc:爆炸粒子动画效果
 */
public class CustomBoomBallView extends View {

    private static final int IDLE = 0;//初始化状态
    private static final int RUNNING = 1;//动画执行状态

    private int mAnimStatus = IDLE;

    private Paint mPaint;
    private Bitmap mBitmap;//原图

    private float mBallDiameter = 3;//粒子直径
    private ArrayList<Ball> mBalls = new ArrayList<>();//保存粒子的集合

    private ValueAnimator mAnimator;

    public CustomBoomBallView(Context context) {
        this(context, null);
    }

    public CustomBoomBallView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomBoomBallView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.baybay, options);
        initBalls();

        mAnimator = ValueAnimator.ofFloat(0, 1);
        mAnimator.setRepeatCount(-1);
        mAnimator.setDuration(3000);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Log.d("tianzhao", "getDuration=" + animation.getCurrentPlayTime());
                if (animation.getCurrentPlayTime() < 3000){
                    mAnimStatus = RUNNING;
                    updateBall();
                    invalidate();
                } else {
                    initBalls();
                    invalidate();
                    animation.cancel();
                    mAnimStatus = IDLE;
                }

            }
        });

    }

    private void initBalls() {
        for (int x = 0; x < mBitmap.getWidth(); x++) {
            for (int y = 0; y < mBitmap.getHeight(); y++) {
                Ball ball = new Ball();
                ball.color = mBitmap.getPixel(x, y);
                ball.x = x * mBallDiameter + mBallDiameter / 2;
                ball.y = y * mBallDiameter + mBallDiameter / 2;
                ball.r = mBallDiameter / 2;

                ball.vX = (float) (Math.pow(-1, Math.ceil(Math.random() * 1000)) * 20 * Math.random());
                ball.vY = rangInt(-15,35);

                ball.aX = 0;
                ball.aY = 0.98f;

                mBalls.add(ball);
            }
        }
    }

    private int rangInt(int i, int j) {
        int max = Math.max(i, j);
        int min = Math.min(i, j);
        return (int) (min + Math.ceil(Math.random() * (max - min)));
    }

    /**
     * 更新 ball 的位置和速度
     */
    private void updateBall() {
        for (Ball ball : mBalls) {
            ball.x += ball.vX;
            ball.y += ball.vY;

            ball.vX += ball.aX;
            ball.vY += ball.aY;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(300, 300);
        for (Ball ball : mBalls) {
            mPaint.setColor(ball.color);
            canvas.drawCircle(ball.x, ball.y, ball.r, mPaint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mAnimStatus == IDLE) {
                mAnimator.start();
            }
        }
        return super.onTouchEvent(event);
    }

    /**
     * 粒子相关属性
     */
    private static class Ball {

        private int color;//粒子颜色

        private float x;//圆心 x 坐标
        private float y;//圆心 y 坐标
        private float r;//粒子半径

        private float vX;//水平方向 速度
        private float vY;//垂直方向 速度
        private float aX;//水平方向 加速度
        private float aY;//垂直方向 加速度
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值