Skip to content

Instantly share code, notes, and snippets.

@stevenosse
Created June 20, 2024 21:54
Show Gist options
  • Save stevenosse/5c1b93e95f7face0ec16e954b868519c to your computer and use it in GitHub Desktop.
Save stevenosse/5c1b93e95f7face0ec16e954b868519c to your computer and use it in GitHub Desktop.
Confetti V2
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: ConfettiWidget(
numberOfParticles: 500,
particleTemplates: [
Icon(Icons.star, color: Colors.red, size: 10),
Icon(Icons.favorite, color: Colors.pink, size: 10),
Icon(Icons.circle, color: Colors.blue, size: 10),
Icon(Icons.square, color: Colors.green, size: 10),
],
minSize: 5.0,
maxSize: 15.0,
duration: Duration(seconds: 5),
gravity: 0.05,
loop: false,
),
),
),
);
}
}
class ConfettiWidget extends StatefulWidget {
final int numberOfParticles;
final List<Widget> particleTemplates;
final double minSize;
final double maxSize;
final Duration duration;
final double gravity;
final bool loop;
const ConfettiWidget({
Key? key,
this.numberOfParticles = 300,
required this.particleTemplates,
this.minSize = 5.0,
this.maxSize = 15.0,
this.duration = const Duration(seconds: 5),
this.gravity = 0.05,
this.loop = false,
}) : super(key: key);
@override
_ConfettiWidgetState createState() => _ConfettiWidgetState();
}
class _ConfettiWidgetState extends State<ConfettiWidget> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late List<Particle> _particles;
final Random _random = Random();
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: widget.duration,
);
if (widget.loop) {
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reset();
_initializeParticles();
_controller.forward();
}
});
}
_controller.addListener(() => setState(() {}));
_initializeParticles();
_controller.forward();
}
void _initializeParticles() {
_particles = List.generate(widget.numberOfParticles, (_) => Particle(
_random,
widget.particleTemplates[_random.nextInt(widget.particleTemplates.length)],
widget.minSize,
widget.maxSize,
widget.gravity,
));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: _particles.map((particle) {
particle.update(_controller.value);
return Positioned(
left: particle.x * constraints.maxWidth,
top: particle.y * constraints.maxHeight,
child: Transform.scale(
scale: particle.size / 10, // Assuming original template size is 10
child: particle.template,
),
);
}).toList(),
);
},
);
}
}
class Particle {
double x;
double y;
Widget template;
double size;
double velocity;
double radians;
double gravity;
Particle(Random random, this.template, double minSize, double maxSize, this.gravity)
: x = random.nextBool() ? random.nextDouble() * 0.1 : 1 - random.nextDouble() * 0.1,
y = 1.0,
size = random.nextDouble() * (maxSize - minSize) + minSize,
velocity = random.nextDouble() * 0.5 + 0.1,
radians = random.nextDouble() * (pi / 2) + (pi / 4);
void update(double progress) {
x += cos(radians) * velocity * progress;
y -= sin(radians) * velocity * progress;
y += gravity * progress;
velocity *= 0.98;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment