Skip to content

Instantly share code, notes, and snippets.

@pskink
Last active October 1, 2024 07:51
Show Gist options
  • Save pskink/f80b86cb98839ce74cc78e307a6412fb to your computer and use it in GitHub Desktop.
Save pskink/f80b86cb98839ce74cc78e307a6412fb to your computer and use it in GitHub Desktop.
import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
void main() => runApp(MaterialApp(home: Scaffold(body: Foo())));
class Foo extends StatefulWidget {
@override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> with TickerProviderStateMixin {
late final controller = AnimationController(vsync: this, duration: Durations.extralong4 * 3);
@override
Widget build(BuildContext context) {
return Column(
children: [
ElevatedButton(
onPressed: () => controller.forward(from: 0),
child: Text('animate for ${controller.duration!.inMilliseconds}ms'),
),
Expanded(
child: ClipRect(
child: CustomPaint(
painter: FooPainter(controller),
child: const SizedBox.expand(),
),
),
),
],
);
}
}
class FooPainter extends CustomPainter {
FooPainter(this.controller) : super(repaint: controller) {
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
// different shapes of 'point':
(switch (1) {
// filled circle
0 => const ShapeDecoration(color: Colors.black, shape: CircleBorder()),
// outlined circle
1 => const ShapeDecoration(shape: CircleBorder(side: BorderSide(color: Colors.black, width: R * 0.6))),
// 8-pointed star
_ => const ShapeDecoration(color: Colors.black, shape: StarBorder(points: 8, innerRadiusRatio: 0.6)),
})
.createBoxPainter(() {})
.paint(canvas, Offset.zero, const ImageConfiguration(size: Size.fromRadius(R)));
image = recorder.endRecording().toImageSync((2 * R).ceil(), (2 * R).ceil());
}
static const R = 6.0; // radius
static const D = 3.0; // delta +/-
static const N = 1000;
final AnimationController controller;
late ui.Image image;
final rnd = Random();
List<ui.Offset>? offsets;
final rects = List.filled(N, Offset.zero & const Size.fromRadius(R));
final colors = List.generate(N, (i) => HSVColor.fromAHSV(1, 120 * i / N, 1, 0.8).toColor());
@override
void paint(Canvas canvas, Size size) {
offsets ??= [ // initialize offsets
for (int i = 0; i < N; i++)
Offset(rnd.nextDouble() * size.width, rnd.nextDouble() * size.height)
];
if (controller.isAnimating) {
offsets = [ // update offsets by random delta
...offsets!.mapIndexed((i, o) {
final factor = D * ui.lerpDouble(1, 2, colors[i].green / 255)!;
final x = (o.dx + factor * ui.lerpDouble(-1, 1, rnd.nextDouble())!).clamp(0.0, size.width);
final y = (o.dy + factor * ui.lerpDouble(-1, 1, rnd.nextDouble())!).clamp(0.0, size.height);
return Offset(x, y);
})
];
}
List<ui.RSTransform> transforms = [
...offsets!.map((o) => ui.RSTransform(1, 0, o.dx - R, o.dy - R))
];
canvas.drawAtlas(image, transforms, rects, colors, BlendMode.dstATop, null, Paint());
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment