1、先绘制背景画布,以及本地绘制图片
/// 继承 CustomPainter
class Playground extends CustomPainter {
final ui.Image? image;
/// 用于矩阵变化(也可以是动画Animation)
final ValueListenable<Matrix4>? matrix;
Playground({
this.image,
this.matrix,
}) : super(repaint: matrix);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint()
..style = PaintingStyle.stroke
..color = Colors.redAccent;
/// 绘制背景画布
canvas.drawRect(Offset.zero & size, paint);
/// 绘制本地图片
if (image != null && matrix != null) {
canvas.save(); // save() 操作会保存此前的所有绘制内容和 Canvas 状态。
canvas.transform(matrix!.value.storage); // 可以通过 Matrix4 矩阵进行变换。而矩阵可以通过乘法进行变换的叠加
drawCarImage(canvas, paint);
canvas.restore(); // 当你调用 restore() 之后,会把 save() 到 restore() 之间所进行的操作与之前的内容进行合并。
}
}
@override
bool shouldRepaint(covariant Playground oldDelegate) {
return true;
}
/// 绘制本地车子图片
drawCarImage(Canvas canvas, Paint paint) {
// 给车子绘制边框
Rect rect = Rect.fromLTWH(0, 0, image!.width.toDouble(), image!.height.toDouble());
paint.color = Colors.orangeAccent;
canvas.drawRect(rect, paint);
/// 绘制本地图片
canvas.drawImage(image!, Offset.zero, paint);
}
}
2、需要创建的对象
late final AnimationController _animationController;
/// 最终得到的矩阵
final ValueNotifier<Matrix4> _matrix = ValueNotifier(Matrix4.identity());
/// 记录最后一次的运动,用于叠加上一次运动使用
late Matrix4 _lastMatrix = Matrix4.identity();
3、向前移动动画
void _onMove() {
Matrix4 move = Matrix4.translationValues(20, 0, 0);
// copy 最后一次运动矩阵
Matrix4 copy = _lastMatrix.clone();
// 补间动画
Animation<Matrix4> anim = Matrix4Tween(begin: Matrix4.translationValues(0, 0, 0), end: move).animate(_animationController);
anim.addListener(() {
_matrix.value = copy.multiplied(anim.value); // 叠加矩阵
});
anim.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// 记录最后一次运行
_lastMatrix = _matrix.value;
}
});
// 执行动画
_animationController.forward(from: 0);
}
4、旋转动画,需要明白画布的变化中心概念
void _onRotate() {
/// 初始化矩阵
/// 平移变换可以影响变换中心, 为了抵消平移变换带来的后果,在旋转之后,反向平移即可
/// 处理最后一次操作(修改变换中心,先平移后旋转,再恢复平移)
Matrix4 rotate90 = Matrix4.rotationZ(pi / 2);
Matrix4 moveCenter = Matrix4.translationValues(50, 50, 0); // 平移距离最好是图片宽高的一半
Matrix4 centerBack = Matrix4.translationValues(-50, -50, 0);
/// copy最后一次的运行矩阵
Matrix4 copy = _lastMatrix.clone();
/// 补间动画
Animation<Matrix4> anim = Matrix4Tween(begin: Matrix4.rotationZ(0), end: rotate90).animate(_animationController);
anim.addListener(() {
// 进行变化中心的改变
Matrix4 matrix4 = moveCenter.multiplied(anim.value).multiplied(centerBack);
_matrix.value = copy.multiplied(matrix4); // 叠加矩阵
});
anim.addStatusListener((status) {
if (status == AnimationStatus.completed) {
// 记录最后一次运动矩阵
_lastMatrix = _matrix.value;
}
});
// 执行动画
_animationController.forward(from: 0);
}
5、复原
void _onReset() {
_matrix.value = Matrix4.identity();
_lastMatrix = Matrix4.identity();
}
学习的代码:https://gitee.com/StephenTom/flutter_learn_canvas.git