import 'dart:math'; import 'package:flutter/material.dart'; class Bubbles extends StatefulWidget { @override State createState() { return _BubblesState(); } } class Bubble { Offset speed; Offset location; double radius; double life; Color color; double opacity; double remainingLife; Bubble() { Random rd = Random(); this.speed = Offset(-0.5 + rd.nextDouble(), -0.5 + rd.nextDouble()); this.location = Offset(32.0, 32.0); this.radius = 8.0 + rd.nextDouble() * 16; this.life = rd.nextDouble() * 20; this.remainingLife = this.life; this.color = const Color(0xFF6fa1ea); } move() { this.remainingLife -= 0.1; this.location = this.location + this.speed; } display(Canvas canvas) { this.opacity = (this.remainingLife / this.life * 100).round() / 100; var gradient = RadialGradient( colors: [ Color.fromRGBO( this.color.red, this.color.green, this.color.blue, this.opacity), Color.fromRGBO( this.color.red, this.color.green, this.color.blue, this.opacity), Color.fromRGBO(this.color.red, this.color.green, this.color.blue, 0.0) ], stops: [0.0, 0.5, 1.0], ); Paint painter = Paint() ..style = PaintingStyle.fill ..shader = gradient.createShader( Rect.fromCircle(center: this.location, radius: this.radius)); canvas.drawCircle(this.location, this.radius, painter); } } class _BubblesState extends State with TickerProviderStateMixin { AnimationController animationController; final bubbles = []; @override void initState() { super.initState(); List.generate(5, (i) { bubbles.add(Bubble()); }); animationController = AnimationController(vsync: this, duration: Duration(milliseconds: 1000)) ..addListener(() { for (int i = 0; i < bubbles.length; i++) { bubbles[i].move(); if (bubbles[i].remainingLife < 0 || bubbles[i].radius < 0) { bubbles[i] = Bubble(); } } }) ..repeat(); } @override void dispose() { animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: animationController, builder: (context, child) => CustomPaint( size: Size(64.0, 64.0), painter: _BubblePainter(bubbles), ), ); } } class _BubblePainter extends CustomPainter { final List bubbles; _BubblePainter(this.bubbles); @override void paint(Canvas canvas, Size size) { for (var bubble in bubbles) { bubble.display(canvas); } } @override bool shouldRepaint(_BubblePainter oldDelegate) => true; }