本片文章讲解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);
}
}