1.2.3Canvas高阶使用技巧-变换,状态保存,离屏缓冲,粒子特效

本片文章讲解Canvas的高级使用,可以参考这篇文章:https://www.cnblogs.com/tianzhijiexian/p/4300988.html

Canvas所提供的各种方法根据功能来看大致可以分为几类:

第一是以drawXXX为主的绘制方法;

第二是以clipXXX为主的裁剪方法;

第三是以scale、skew、translate和rotate组成的Canvas变换方法;

最后一类则是以saveXXX和restoreXXX构成的画布锁定和还原;

还有一些其他的就不归类了。

 

Canvas的基本使用

直接贴代码,看效果:

CanvasDemo


/**
 * Canvas所提供的各种方法根据功能来看大致可以分为几类:
 * 第一是以drawXXX为主的绘制方法;
 * 第二是以clipXXX为主的裁剪方法;
 * 第三是以scale、skew、translate和rotate组成的Canvas变换方法;
 * 最后一类则是以saveXXX和restoreXXX构成的画布锁定和还原;
 * 还有一些其他的就不归类了。
 */
public class CanvasDemo extends View {
    private Paint mPaint;
    private Bitmap mBitmap;

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

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

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

    private void init() {
        mPaint = new Paint();//初始化
        mPaint.setColor(Color.RED);//设置颜色
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(2);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.cat);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        //1. 平移操作
       /* canvas.drawRect(0, 0, 300, 300, mPaint);
        canvas.translate(10, 10);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(0, 0, 300, 300, mPaint);*/

        //2. 缩放操作
        /*canvas.drawRect(100, 100, 300, 300, mPaint);
        //canvas.scale(0.5f, 0.5f);
        //重载方法,先缩放再平移 px=100,实际在画布上是50
        canvas.scale(0.5f, 0.5f, 100, 100);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(100, 100, 300, 300, mPaint);*/

        //3. 旋转操作
        /*canvas.drawRect(100, 100, 300, 300, mPaint);
        //顺时针旋转45度
        canvas.rotate(45, 200, 200);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(100, 100, 300, 300, mPaint);*/

        //4. 倾斜操作
        /*canvas.save();
        canvas.drawRect(0, 0, 300, 300, mPaint);
        //x方向倾斜45度
        canvas.skew(1, 0);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(0, 0, 300, 300, mPaint);
        //y方向倾斜45度
        canvas.restore();
        canvas.skew(0, 1.3f);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(0, 0, 300, 300, mPaint);*/

        //5. 切割操作
        //clipXxx:参数指定区域内可绘制
        //clipOutXxx:参数指定区域内不可绘制
        /*canvas.drawRect(50, 50, 250, 250, mPaint);
        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(70, 70, 20, mPaint);
        //切割操作,区域内可继续绘制
        canvas.clipRect(50, 50, 250, 250);
        //反向裁剪>Android O
        //canvas.clipOutRect(50, 50, 250, 250);
        mPaint.setColor(Color.GREEN);
        canvas.drawCircle(180, 180, 20, mPaint);
        mPaint.setColor(Color.GRAY);
        //只能画到框内
        canvas.drawCircle(200, 200, 100, mPaint);*/

        //6. 矩阵Matrix,可以通过矩阵来实现平移、缩放、旋转等
        /*canvas.drawRect(0, 0, 300, 300, mPaint);
        Matrix matrix = new Matrix();
        matrix.setTranslate(10, 0);
        //matrix.setScale(0.5f, 0.5f);
        canvas.setMatrix(matrix);
        mPaint.setColor(Color.BLUE);
        canvas.drawRect(0, 0, 300, 300, mPaint);*/

        //7. 状态的保存与恢复
        int save = canvas.save();
        canvas.drawRect(100, 100, 300, 300, mPaint);
        canvas.translate(10, 10);
        mPaint.setColor(Color.BLUE);
        canvas.drawLine(0, 0, 100, 100, mPaint);
        canvas.restore();
        mPaint.setColor(Color.GREEN);
        canvas.drawLine(0, 0, 300, 100, mPaint);
    }


}

 

粒子特效

接下来我们要用学到的东西做出一个特效:

粒子封装对象类Ball:

/**
 * 粒子封装对象
 */
public class Ball {

    public int color; //图片像素点颜色值
    public float x; //粒子圆心坐标x
    public float y; //粒子圆心坐标y
    public float r; //粒子半径

    public float vX;//粒子运动水平方向速度
    public float vY;//粒子运动垂直方向速度
    public float aX;//粒子运动水平方向加速度
    public float aY;//粒子运动垂直方向加速度
}

粒子动画实现类ExplosionDemo:

public class ExplosionDemo extends View {
    private Paint mPaint;
    private Bitmap mBitmap;
    private float ballWidth = 1;//粒子直径
    private List<Ball> mBalls = new ArrayList<>();
    private ValueAnimator mAnimator;

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

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

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

    private void init() {
        mPaint = new Paint();//初始化
        mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.man);

        //分解图片将数据封装到List中
        splitBitmapToBall();
        //定义一个属性动画
        mAnimator = ValueAnimator.ofFloat(0, 1);
        mAnimator.setRepeatCount(0);
        mAnimator.setDuration(2000);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                updateBall();
                invalidate();
            }
        });
        mAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                splitBitmapToBall();
                invalidate();
            }
        });

    }

    private void splitBitmapToBall() {
        mBalls.clear();
        int width = mBitmap.getWidth();
        int height = mBitmap.getHeight();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                int color = mBitmap.getPixel(i, j);
                Ball ball = new Ball();
                ball.color = color;
                ball.x = i * ballWidth + ballWidth / 2;
                ball.y = j * ballWidth + ballWidth / 2;
                ball.r = ballWidth / 2;

                //速度(-20,20)
                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 void updateBall() {
        //更新粒子的位置
        for (Ball ball : mBalls) {
            ball.x += ball.vX;
            ball.y += ball.vY;
            ball.vX += ball.aX;
            ball.vY += ball.aY;
        }
    }

    private int rangInt(int i, int j) {
        int max = Math.max(i, j);
        int min = Math.min(i, j) - 1;
        //在0到(max - min)范围内变化,取大于x的最小整数 再随机
        return (int) (min + Math.ceil(Math.random() * (max - min)));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画原图
        canvas.drawBitmap(mBitmap, 10, 10, mPaint);

        //移动一下画布
        canvas.translate(200, 250);
        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 (mAnimator != null) {
                mAnimator.start();
            }
        }
        return super.onTouchEvent(event);
    }
}

 

 

 

END

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值