'How to create Confetti animation in Flutter

I want to a make Confetti effect animation in my flutter app?

How to Explore Confetti Animation In Flutter and how to add the confetti animation and show a colorful blast in our flutter applications.



Solution 1:[1]

Here is a process of achieving the Confetti effect animation

First make two enum for BlastDirectionality

enum BlastDirectionality {
  directional,
  explosive,
}

enum ConfettiControllerState {
  playing,
  stopped,
}

Create a ConfettiWidget class

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:prokit_flutter/main/utils/confetti/src/particle.dart';

import 'enums/blast_directionality.dart';
import 'enums/confetti_controller_state.dart';

class ConfettiWidget extends StatefulWidget {
  const ConfettiWidget({
    Key key,
    @required this.confettiController,
    this.emissionFrequency = 0.02,
    this.numberOfParticles = 10,
    this.maxBlastForce = 20,
    this.minBlastForce = 5,
    this.blastDirectionality = BlastDirectionality.directional,
    this.blastDirection = pi,
    this.gravity = 0.2,
    this.shouldLoop = false,
    this.displayTarget = false,
    this.colors,
    this.minimumSize = const Size(20, 10),
    this.maximumSize = const Size(30, 15),
    this.particleDrag = 0.05,
    this.canvas,
    this.child,
  })  : assert(
            confettiController != null,
            emissionFrequency != null &&
                numberOfParticles != null &&
                maxBlastForce != null &&
                minBlastForce != null &&
                blastDirectionality != null &&
                blastDirection != null),
        assert(emissionFrequency >= 0 &&
            emissionFrequency <= 1 &&
            numberOfParticles > 0 &&
            maxBlastForce > 0 &&
            minBlastForce > 0 &&
            maxBlastForce > minBlastForce),
        assert(gravity >= 0 && gravity <= 1),
        super(key: key);

  final ConfettiController confettiController;

  final double maxBlastForce;

  final double minBlastForce;

  final BlastDirectionality blastDirectionality;

  final double blastDirection;
  final double gravity;
  final double emissionFrequency;
  final int numberOfParticles;
  final bool shouldLoop;
  final bool displayTarget;

  final List<Color> colors;
  final Size minimumSize;
  final Size maximumSize;

  final double particleDrag;
  final Size canvas;

  final Widget child;

  @override
  _ConfettiWidgetState createState() => _ConfettiWidgetState();
}

class _ConfettiWidgetState extends State<ConfettiWidget>
    with SingleTickerProviderStateMixin {
  final GlobalKey _particleSystemKey = GlobalKey();

  AnimationController _animController;
  Animation<double> _animation;
  ParticleSystem _particleSystem;

  Offset _emitterPosition;

  Size _screenSize = const Size(0, 0);

  @override
  void initState() {
    widget.confettiController.addListener(_handleChange);

    _particleSystem = ParticleSystem(
        emissionFrequency: widget.emissionFrequency,
        numberOfParticles: widget.numberOfParticles,
        maxBlastForce: widget.maxBlastForce,
        minBlastForce: widget.minBlastForce,
        gravity: widget.gravity,
        blastDirection: widget.blastDirection,
        blastDirectionality: widget.blastDirectionality,
        colors: widget.colors,
        minimumSize: widget.minimumSize,
        maximumsize: widget.maximumSize,
        particleDrag: widget.particleDrag);

    _particleSystem.addListener(_particleSystemListener);

    _initAnimation();
    super.initState();
  }

  void _initAnimation() {
    _animController = AnimationController(
        vsync: this, duration: widget.confettiController.duration);
    _animation = Tween<double>(begin: 0, end: 1).animate(_animController);
    _animation.addListener(_animationListener);
    _animation.addStatusListener(_animationStatusListener);

    if (widget.confettiController.state == ConfettiControllerState.playing) {
      _startAnimation();
      _startEmission();
    }
  }

  void _handleChange() {
    if (widget.confettiController.state == ConfettiControllerState.playing) {
      _startAnimation();
      _startEmission();
    } else if (widget.confettiController.state ==
        ConfettiControllerState.stopped) {
      _stopEmission();
    }
  }

  void _animationListener() {
    if (_particleSystem.particleSystemStatus == ParticleSystemStatus.finished) {
      _animController.stop();
      return;
    }
    _particleSystem.update();
  }

  void _animationStatusListener(AnimationStatus status) {
    if (status == AnimationStatus.completed) {
      if (!widget.shouldLoop) {
        _stopEmission();
      }
      _continueAnimation();
    }
  }

  void _particleSystemListener() {
    if (_particleSystem.particleSystemStatus == ParticleSystemStatus.finished) {
      _stopAnimation();
    }
  }

  void _startEmission() {
    _particleSystem.startParticleEmission();
  }

  void _stopEmission() {
    if (_particleSystem.particleSystemStatus == ParticleSystemStatus.stopped) {
      return;
    }
    _particleSystem.stopParticleEmission();
  }

  void _startAnimation() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _setScreenSize();
      _setEmitterPosition();
      _animController.forward(from: 0);
    });
  }

  void _stopAnimation() {
    _animController.stop();
  }

  void _continueAnimation() {
    _animController.forward(from: 0);
  }

  void _setScreenSize() {
    _screenSize = _getScreenSize();
    _particleSystem.screenSize = _screenSize;
  }

  void _setEmitterPosition() {
    _emitterPosition = _getContainerPosition();
    _particleSystem.particleSystemPosition = _emitterPosition;
  }

  Offset _getContainerPosition() {
    final RenderBox containerRenderBox =
        _particleSystemKey.currentContext.findRenderObject();
    return containerRenderBox.localToGlobal(Offset.zero);
  }

  Size _getScreenSize() {
    return widget.canvas ?? MediaQuery.of(context).size;
  }

  void _updatePositionAndSize() {
    if (_getScreenSize() != _screenSize) {
      _setScreenSize();
      if (_emitterPosition != null) {
        _setEmitterPosition();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    _updatePositionAndSize();
    return RepaintBoundary(
      child: CustomPaint(
        key: _particleSystemKey,
        foregroundPainter: ParticlePainter(
          _animController,
          particles: _particleSystem.particles,
          paintEmitterTarget: widget.displayTarget,
        ),
        child: widget.child,
      ),
    );
  }

  @override
  void dispose() {
    widget.confettiController.stop();
    _animController.dispose();
    widget.confettiController.removeListener(_handleChange);
    _particleSystem.removeListener(_particleSystemListener);
    _particleSystem = null;
    super.dispose();
  }
}

class ParticlePainter extends CustomPainter {
  ParticlePainter(Listenable repaint,
      {@required this.particles,
      paintEmitterTarget = true,
      emitterTargetColor = Colors.black})
      : _paintEmitterTarget = paintEmitterTarget,
        _emitterPaint = Paint()
          ..color = emitterTargetColor
          ..style = PaintingStyle.stroke
          ..strokeWidth = 2.0,
        _particlePaint = Paint()
          ..color = Colors.green
          ..style = PaintingStyle.fill,
        super(repaint: repaint);

  final List<Particle> particles;

  final Paint _emitterPaint;
  final bool _paintEmitterTarget;
  final Paint _particlePaint;

  @override
  void paint(Canvas canvas, Size size) {
    if (_paintEmitterTarget) {
      _paintEmitter(canvas);
    }
    if (particles == null) {
      return;
    }
    _paintParticles(canvas);
  }

  void _paintEmitter(Canvas canvas) {
    const radius = 10.0;
    canvas.drawCircle(Offset.zero, radius, _emitterPaint);
    final path = Path();
    path.moveTo(0, -radius);
    path.lineTo(0, radius);
    path.moveTo(-radius, 0);
    path.lineTo(radius, 0);
    canvas.drawPath(path, _emitterPaint);
  }

  void _paintParticles(Canvas canvas) {
    for (final particle in particles) {
      final rotationMatrix4 = Matrix4.identity();
      rotationMatrix4
        ..translate(particle.location.dx, particle.location.dy)
        ..rotateX(particle.angleX)
        ..rotateY(particle.angleY)
        ..rotateZ(particle.angleZ);

      final finalPath = particle.path.transform(rotationMatrix4.storage);
      canvas.drawPath(finalPath, _particlePaint..color = particle.color);
    }
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

class ConfettiController extends ChangeNotifier {
  ConfettiController({this.duration = const Duration(seconds: 30)})
      : assert(duration != null &&
            !duration.isNegative &&
            duration.inMicroseconds > 0);

  Duration duration;

  ConfettiControllerState _state = ConfettiControllerState.stopped;

  ConfettiControllerState get state => _state;

  void play() {
    _state = ConfettiControllerState.playing;
    notifyListeners();
  }

  void stop() {
    _state = ConfettiControllerState.stopped;
    notifyListeners();
  }
}

Make a Helper class

import 'dart:math';
import 'dart:ui' as ui;

final _rand = Random();

double randomize(double min, double max) {
  return ui.lerpDouble(min, max, _rand.nextDouble());
}

void debugPrint(String message) {
  assert(() {
    print('__debug__confetti__$message');
    return true;
  }());
}

Create one more class ParticleSystem

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:prokit_flutter/main/utils/confetti/src/helper.dart';
import 'package:prokit_flutter/main/utils/randomcolor/random_color.dart';

import 'package:vector_math/vector_math.dart' as vmath;

import 'enums/blast_directionality.dart';

enum ParticleSystemStatus {
  started,
  finished,
  stopped,
}

class ParticleSystem extends ChangeNotifier {
  ParticleSystem(
      {@required double emissionFrequency,
      @required int numberOfParticles,
      @required double maxBlastForce,
      @required double minBlastForce,
      @required double blastDirection,
      @required BlastDirectionality blastDirectionality,
      @required List<Color> colors,
      @required Size minimumSize,
      @required Size maximumsize,
      @required double particleDrag,
      @required double gravity})
      : assert(
          emissionFrequency != null &&
              numberOfParticles != null &&
              maxBlastForce != null &&
              minBlastForce != null &&
              blastDirection != null &&
              minimumSize != null &&
              maximumsize != null &&
              particleDrag != null &&
              blastDirectionality != null,
        ),
        assert(maxBlastForce > 0 &&
            minBlastForce > 0 &&
            emissionFrequency >= 0 &&
            emissionFrequency <= 1 &&
            numberOfParticles > 0 &&
            minimumSize.width > 0 &&
            minimumSize.height > 0 &&
            maximumsize.width > 0 &&
            maximumsize.height > 0 &&
            minimumSize.width <= maximumsize.width &&
            minimumSize.height <= maximumsize.height &&
            particleDrag >= 0.0 &&
            particleDrag <= 1 &&
            minimumSize.height <= maximumsize.height),
        assert(gravity >= 0 && gravity <= 1),
        _blastDirection = blastDirection,
        _blastDirectionality = blastDirectionality,
        _gravity = gravity,
        _maxBlastForce = maxBlastForce,
        _minBlastForce = minBlastForce,
        _frequency = emissionFrequency,
        _numberOfParticles = numberOfParticles,
        _colors = colors,
        _minimumSize = minimumSize,
        _maximumSize = maximumsize,
        _particleDrag = particleDrag,
        _rand = Random();

  ParticleSystemStatus _particleSystemStatus;

  final List<Particle> _particles = [];
  final double _frequency;
  final int _numberOfParticles;
  final double _maxBlastForce;
  final double _minBlastForce;
  final double _blastDirection;
  final BlastDirectionality _blastDirectionality;
  final double _gravity;
  final List<Color> _colors;
  final Size _minimumSize;
  final Size _maximumSize;
  final double _particleDrag;

  Offset _particleSystemPosition;
  Size _screenSize;

  double _bottomBorder;
  double _rightBorder;
  double _leftBorder;

  final Random _rand;

  set particleSystemPosition(Offset position) {
    _particleSystemPosition = position;
  }

  set screenSize(Size size) {
    _screenSize = size;
    _setScreenBorderPositions();
  }

  void stopParticleEmission() {
    _particleSystemStatus = ParticleSystemStatus.stopped;
  }

  void startParticleEmission() {
    _particleSystemStatus = ParticleSystemStatus.started;
  }

  void finishParticleEmission() {
    _particleSystemStatus = ParticleSystemStatus.finished;
  }

  List<Particle> get particles => _particles;
  ParticleSystemStatus get particleSystemStatus => _particleSystemStatus;

  void update() {
    _clean();
    if (_particleSystemStatus != ParticleSystemStatus.finished) {
      _updateParticles();
    }

    if (_particleSystemStatus == ParticleSystemStatus.started) {
      if (particles.isEmpty) {
        _particles.addAll(_generateParticles(number: _numberOfParticles));
        return;
      }

      final chanceToGenerate = _rand.nextDouble();
      if (chanceToGenerate < _frequency) {
        _particles.addAll(_generateParticles(number: _numberOfParticles));
      }
    }

    if (_particleSystemStatus == ParticleSystemStatus.stopped &&
        _particles.isEmpty) {
      finishParticleEmission();
      notifyListeners();
    }
  }

  void _setScreenBorderPositions() {
    _bottomBorder = _screenSize.height * 1.1;
    _rightBorder = _screenSize.width * 1.1;
    _leftBorder = _screenSize.width - _rightBorder;
  }

  void _updateParticles() {
    if (particles == null) {
      return;
    }
    for (final particle in _particles) {
      particle.update();
    }
  }

  void _clean() {
    if (_particleSystemPosition != null &&
        _screenSize != null &&
        particles != null) {
      _particles
          .removeWhere((particle) => _isOutsideOfBorder(particle.location));
    }
  }

  bool _isOutsideOfBorder(Offset particleLocation) {
    final globalParticlePosition = particleLocation + _particleSystemPosition;
    return (globalParticlePosition.dy >= _bottomBorder) ||
        (globalParticlePosition.dx >= _rightBorder) ||
        (globalParticlePosition.dx <= _leftBorder);
  }

  List<Particle> _generateParticles({int number = 1}) {
    return List<Particle>.generate(
        number,
        (i) => Particle(_generateParticleForce(), _randomColor(), _randomSize(),
            _gravity, _particleDrag));
  }

  double get _randomBlastDirection =>
      vmath.radians(Random().nextInt(359).toDouble());

  vmath.Vector2 _generateParticleForce() {
    var blastDirection = _blastDirection;
    if (_blastDirectionality == BlastDirectionality.explosive) {
      blastDirection = _randomBlastDirection;
    }
    final blastRadius = randomize(_minBlastForce, _maxBlastForce);
    final y = blastRadius * sin(blastDirection);
    final x = blastRadius * cos(blastDirection);
    return vmath.Vector2(x, y);
  }

  Color _randomColor() {
    if (_colors != null) {
      if (_colors.length == 1) {
        return _colors[0];
      }
      final index = _rand.nextInt(_colors.length);
      return _colors[index];
    }
    return RandomColor().randomColor();
  }

  Size _randomSize() {
    return Size(
      randomize(_minimumSize.width, _maximumSize.width),
      randomize(_minimumSize.height, _maximumSize.height),
    );
  }
}

class Particle {
  Particle(vmath.Vector2 startUpForce, Color color, Size size, double gravity,
      double particleDrag)
      : _startUpForce = startUpForce,
        _color = color,
        _mass = randomize(1, 11),
        _particleDrag = particleDrag,
        _location = vmath.Vector2.zero(),
        _acceleration = vmath.Vector2.zero(),
        _velocity = vmath.Vector2(randomize(-3, 3), randomize(-3, 3)),
        _pathShape = createPath(size),
        _aVelocityX = randomize(-0.1, 0.1),
        _aVelocityY = randomize(-0.1, 0.1),
        _aVelocityZ = randomize(-0.1, 0.1),
        _gravity = lerpDouble(0.1, 5, gravity);

  final vmath.Vector2 _startUpForce;

  final vmath.Vector2 _location;
  final vmath.Vector2 _velocity;
  final vmath.Vector2 _acceleration;

  final double _particleDrag;
  double _aX = 0;
  double _aVelocityX;
  double _aY = 0;
  double _aVelocityY;
  double _aZ = 0;
  double _aVelocityZ;
  final double _gravity;
  final _aAcceleration = 0.0001;

  final Color _color;
  final double _mass;
  final Path _pathShape;

  double _timeAlive = 0;

  static Path createPath(Size size) {
    final pathShape = Path();
    pathShape.moveTo(0, 0);
    pathShape.lineTo(-size.width, 0);
    pathShape.lineTo(-size.width, size.height);
    pathShape.lineTo(0, size.height);
    pathShape.close();
    return pathShape;
  }

  void applyForce(vmath.Vector2 force) {
    final f = force.clone();
    f.divide(vmath.Vector2.all(_mass));
    _acceleration.add(f);
  }

  void drag() {
    final speed = sqrt(pow(_velocity.x, 2) + pow(_velocity.y, 2));
    final dragMagnitude = _particleDrag * speed * speed;
    final drag = _velocity.clone();
    drag.multiply(vmath.Vector2.all(-1));
    drag.normalize();
    drag.multiply(vmath.Vector2.all(dragMagnitude));
    applyForce(drag);
  }

  void _applyStartUpForce() {
    applyForce(_startUpForce);
  }

  void _applyWindForceUp() {
    applyForce(vmath.Vector2(0, -1));
  }

  void update() {
    drag();

    if (_timeAlive < 5) {
      _applyStartUpForce();
    }
    if (_timeAlive < 25) {
      _applyWindForceUp();
    }

    _timeAlive += 1;

    applyForce(vmath.Vector2(0, _gravity));

    _velocity.add(_acceleration);
    _location.add(_velocity);
    _acceleration.setZero();

    _aVelocityX += _aAcceleration / _mass;
    _aVelocityY += _aAcceleration / _mass;
    _aVelocityZ += _aAcceleration / _mass;
    _aX += _aVelocityX;
    _aY += _aVelocityY;
    _aZ += _aVelocityZ;
  }

  Offset get location {
    if (_location.x.isNaN || _location.y.isNaN) {
      return const Offset(0, 0);
    }
    return Offset(_location.x, _location.y);
  }

  Color get color => _color;
  Path get path => _pathShape;

  double get angleX => _aX;
  double get angleY => _aY;
  double get angleZ => _aZ;
}

And import all those files and use them on your screen as

class CHomePage extends StatefulWidget {
  static String tag = '/CHomePage';

  @override
  _CHomePageState createState() => _CHomePageState();
}

class _CHomePageState extends State<CHomePage> {
  ConfettiController _controllerCenter;
  ConfettiController _controllerCenterRight;
  ConfettiController _controllerCenterLeft;
  ConfettiController _controllerTopCenter;
  ConfettiController _controllerBottomCenter;

  @override
  void initState() {
    _controllerCenter =
        ConfettiController(duration: const Duration(seconds: 5));
    _controllerCenterRight =
        ConfettiController(duration: const Duration(seconds: 5));
    _controllerCenterLeft =
        ConfettiController(duration: const Duration(seconds: 5));
    _controllerTopCenter =
        ConfettiController(duration: const Duration(seconds: 5));
    _controllerBottomCenter =
        ConfettiController(duration: const Duration(seconds: 5));
    super.initState();
  }

  @override
  void dispose() {
    _controllerCenter.dispose();
    _controllerCenterRight.dispose();
    _controllerCenterLeft.dispose();
    _controllerTopCenter.dispose();
    _controllerBottomCenter.dispose();
    super.dispose();
  }

  Text _display(String text) {
    return Text(
      text,
      style: const TextStyle(
        color: Colors.white,
        fontSize: 14,
        fontWeight: FontWeight.bold,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Stack(
          children: <Widget>[
            Container(
              alignment: Alignment.topCenter,
              child: ConfettiWidget(
                confettiController: _controllerCenter,
                blastDirectionality: BlastDirectionality.explosive,
                shouldLoop: false,
                emissionFrequency: 0.1,
                canvas:
                    Size.fromRadius(MediaQuery.of(context).size.height * .35),
                colors: const [
                  Colors.green,
                  Colors.blue,
                  Colors.pink,
                  Colors.orange,
                  Colors.purple
                ], 
              ),
            ),
            Container(
              margin: EdgeInsets.only(bottom: 150),
              alignment: Alignment.bottomCenter,
              child: ConfettiWidget(
                confettiController: _controllerBottomCenter,
                blastDirectionality: BlastDirectionality
                    .explosive, 
                shouldLoop: false,
                emissionFrequency: 0.3,

                canvas: Size.fromRadius(350),
                colors: const [
                  Colors.green,
                  Colors.blue,
                  Colors.pink,
                  Colors.orange,
                  Colors.purple
                ],
              ),
            ),
            Container(
              alignment: Alignment.centerRight,
              child: ConfettiWidget(
                confettiController: _controllerCenterRight,
                blastDirectionality: BlastDirectionality
                    .explosive, 
                shouldLoop: false, 
                emissionFrequency: 0.2,
                canvas:
                    Size.fromRadius(MediaQuery.of(context).size.height * .35),
                colors: const [
                  Colors.black,
                  Colors.redAccent,
                  Colors.tealAccent,
                  Colors.yellowAccent,
                  Colors.orange
                ], 
              ),
            ),
            Container(
              alignment: Alignment.centerLeft,
              child: ConfettiWidget(
                confettiController: _controllerCenterLeft,
                blastDirectionality: BlastDirectionality
                    .explosive,
                shouldLoop: false,
                canvas:
                    Size.fromRadius(MediaQuery.of(context).size.height * .35),
                emissionFrequency: 0.8,
                colors: const [
                  Colors.deepPurple,
                  Colors.yellow,
                  Colors.blueAccent,
                  Colors.green,
                  Colors.purple
                ], 
              ),
            ),
            Container(
              alignment: Alignment.bottomCenter,
              margin: EdgeInsets.only(bottom: 150, left: 15, right: 15),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  Expanded(
                    flex: 1,
                    child: Container(
                      margin: EdgeInsets.only(right: 4),
                      decoration: BoxDecoration(
                          color: Color(0xFF8998FF),
                          borderRadius: BorderRadius.circular(10)),
                      child: FlatButton(
                        onPressed: () {
                          _controllerCenterLeft.play();
                        },
                        child: _display('Left'),
                      ),
                    ),
                  ),
                  Expanded(
                    flex: 1,
                    child: Container(
                      margin: EdgeInsets.only(right: 4),
                      decoration: BoxDecoration(
                          color: Color(0xFF8998FF),
                          borderRadius: BorderRadius.circular(10)),
                      child: FlatButton(
                        onPressed: () {
                          _controllerCenter.play();
                        },
                        child: _display('Top'),
                      ),
                    ),
                  ),
                  Expanded(
                    flex: 1,
                    child: Container(
                      margin: EdgeInsets.only(right: 4),
                      decoration: BoxDecoration(
                          color: Color(0xFF8998FF),
                          borderRadius: BorderRadius.circular(10)),
                      child: FlatButton(
                        onPressed: () {
                          _controllerBottomCenter.play();
                        },
                        child: _display('Bottom'),
                      ),
                    ),
                  ),
                  Expanded(
                    flex: 1,
                    child: Container(
                      decoration: BoxDecoration(
                          color: Color(0xFF8998FF),
                          borderRadius: BorderRadius.circular(10)),
                      child: FlatButton(
                        onPressed: () {
                          _controllerCenterRight.play();
                        },
                        child: _display('Right'),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

enter image description here

Solution 2:[2]

You can use this package - confetti

add below dependency to pubspec.yaml

confetti: ^0.6.0

make ConfettiController Object:

ConfettiController confettiController = new ConfettiController(duration: new Duration(seconds: 5));

Now You can use ConfettiWidget

new ConfettiWidget(
 confettiController: _controllerCenter,
 blastDirectionality: BlastDirectionality.explosive,
 particleDrag: 0.05,
 emissionFrequency: 0.05,
 numberOfParticles: 50,
 gravity: 0.05,
 shouldLoop: true
)

use confettiController.play() to show animation

confettiController.play();

never forget to dispose:

 @override
 void dispose() {
   confettiController.dispose();
   super.dispose();
 }

Full Code

pubspec.yaml

dependencies:
 flutter:
   sdk: flutter
 confetti: ^0.6.0

main.dart

import 'package:flutter/material.dart';
import 'package:confetti/confetti.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Confetti Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final ConfettiController confettiController =
      new ConfettiController(duration: new Duration(seconds: 2));
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: new ConfettiWidget(
          confettiController: confettiController,
          blastDirectionality: BlastDirectionality.explosive,
          particleDrag: 0.05,
          emissionFrequency: 0.05,
          numberOfParticles: 50,
          gravity: 0.05,
          shouldLoop: true,
          child: new Container()),
      floatingActionButton: FloatingActionButton(
        onPressed: () => confettiController.play(),
        tooltip: 'Play',
        child: const Icon(Icons.play_circle),
      ),
    );
  }

  @override
  void dispose() {
    confettiController.dispose();
    super.dispose();
  }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Paresh Mangukiya
Solution 2