近期,我在 FlutterCon Berlin 2023 活动上分享了一次关于通过低级 API 在 Flutter 中制作动画的演讲。准备过程中,内容逐渐扩展到艺术领域,更特别的是生成艺术及其技术历史。
我深受 Vera Molnar 的启发,她是一位90多岁仍然活跃在创作前线的法国匈牙利艺术家。莫尔纳被认为是计算机生成艺术的开创者之一。
从很小的时候起,莫尔纳对随机性充满了兴趣。作为早期采用算法渲染艺术品的先锋,她在计算机生成艺术被认为不人性化时,用机器高效输出的能力证明了这些批评的不正确性。
使用计算机时,你把它作为一种工具,帮助自己将想象力延伸到更广阔的地方。通过它,你能够尽情发挥创造力和好奇心,并在这个媒介中探索远超体力所及的可能性。
莫尔纳多年来一直在不断改进她的生成艺术品方法和设备。事实上,早在她接触计算机的十年前,她就已经开始创作“生成”艺术了。
生成艺术,是指艺术家通过一个系统(如一组自然语言规则、计算机程序或机器)启动并以某种自主性进行创作的实践。
在50年代,莫尔纳提出了“Machine Imaginere”这个概念,即想象之中机器。她使用数学的基本原理和模拟“随机发生器”,如掷骰子,通过逐一修改参数来生成一系列图画,并最终手工制作这些变体。
接触计算机初期,她使用了没有显示器的 IBM 大型机。之后,她使用编程语言如 BASIC 和 Fortran 指导笔式绘图仪,根据程序指令用墨水笔和机器人手臂将代码转换为图画。
了解到用代码进行绘图的历史之久,我深感着迷。莫尔纳和其他杰出艺术家在那个技术受限的时代,通过代码创造出令人惊叹的艺术作品。
如今,非凡的艺术作品利用了现代先进技术制作完成,而 Flutter 通过其强大的跨平台能力和丰富的 API 成为此类工作的理想工具。
受到 Vera Molnar 的艺术风格和理念的启发,我们将通过探索 Flutter 的 CustomPainter 和 Canvas API 来了解生成艺术的一些基本原则,并加入动画使作品活灵活现。
让我们开始编写代码吧!
Flutter 的 CustomPainter 和 Canvas API
在小部件的构建方法中添加 CustomPaint 小部件,并为其提供 CustomPainter 实现。这样可以快速访问 Canvas API,在屏幕上自由绘画。
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: SquareCustomPainter(),
);
}
class SquareCustomPainter extends CustomPainter {
//...
}
CustomPainter 实现包含了两个方法,paint 方法使用 Canvas 执行绘画,shouldRepaint 方法允许您指定何时更新画布。现在可以返回 false。
class SquareCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
//...
}
@override
bool shouldRepaint(covariant SquareCustomPainter oldDelegate) {
return false;
}
}
让我们从简单的开始,在 paint 方法中使用 canvas 的 drawRect API 绘制一个矩形
@override
void paint(Canvas canvas, Size size) {
canvas.drawRect();
}
绘制矩形的方法有很多种。 例如, Rect.fromCenter 可以通过提供矩形中心的坐标及其宽度和高度来绘制矩形。这里我们使用了画布的中心使矩形居中。
@override
void paint(Canvas canvas, Size size) {
final center = Offset(
size.width / 2,
size.height / 2
);
canvas.drawRect(
Rect.fromCenter(
center: center,
width: size.shortestSide * 0.8,
height: size.shortestSide * 0.8,
),
/* ... */,
);
}
然后,您可以添加一个 Paint 对象,您可以从中指定以下属性:
style 采用 PaintingStyle.lines 或 PaintingStyle.fill 枚举值来表示绘画的样式。
根据提供的样式指定填充或描边颜色。
对于描边样式,设置描边宽度。
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 3;
final center = Offset(
size.width / 2,
size.height / 2
);
canvas.drawRect(
Rect.fromCenter(
center: center,
width: size.shortestSide * 0.8,
height: size.shortestSide * 0.8,
),
paint,
);
}
Flutter 文档包含了有用的图像,向您展示了如何使用不同的 API 创建矩形:
让我们使用 fromPoints API 作为另一个示例:
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 3;
final side = size.shortestSide * 0.8;
canvas.drawRect(
Rect.fromPoints(
Offset.zero,
Offset(side, side),
),
paint,
);
}
你会注意到,如果你这样做,矩形会放置在左上角而不是居中。这让我想到了使用画布时的一个重要概念。
使用 Canvas API 居中
当您使用 CustomPainter 或其他自定义 RenderObjects 渲染画布时,它以容器小部件的左上角为起点。您做的任何偏移或平移都是相对于 0,0 点(画布左上角)进行的。
因此,如果您希望绘制居中的内容,您可以:
首先使用 canvas.save() 保存画布的当前状态。
将画布平移到中心偏移位置。
开始绘图。
最后使用 canvas.restore() 重置画布。
canvas.save(); // 1
canvas.translate(center.dx, center.dy); // 2
canvas.drawRect( // 3
Rect.fromPoints(
Offset(-side / 2, -side / 2),
Offset(side / 2, side / 2),
),
paint,
);
canvas.restore(); // 4
生成艺术工具
在生成艺术创作中涉及到一些工具,我会在我们使用 Canvas API 实现这些工具时简要提到一些。
平铺—生成艺术工具 #1
如同平铺墙壁一样,您可以通过水平和垂直重复来平铺艺术品。我们可以通过在画布上创建网格将平铺引入到之前创建的正方形中。通过计算包含 CustomPainter 的小部件中可以水平和垂直放置的正方形数量,再用简单的 for 循环绘制正方形。您可以通过 CustomPainter 的 Paint 方法访问该小部件的大小。
然后我们计算偏移量,以居中绘制这些正方形。
@override
void paint(Canvas canvas, Size size) {
final xCount =
文章为用户上传,仅供非商业浏览。发布者:Lomu,转转请注明出处: https://www.daogebangong.com/articles/detail/Flutter-zhong-de-sheng-cheng-yi-shu.html
评论列表(196条)
测试