Skip to content

Instantly share code, notes, and snippets.

@KanybekMomukeyev
Created April 26, 2020 16:45
Show Gist options
  • Save KanybekMomukeyev/fa92967e82ea32ba1a93f4127f80a687 to your computer and use it in GitHub Desktop.
Save KanybekMomukeyev/fa92967e82ea32ba1a93f4127f80a687 to your computer and use it in GitHub Desktop.
BubbleGum flutter example
import 'dart:async';
import 'dart:math';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: Container(color: Colors.pink[200], child: App()),
debugShowCheckedModeBanner: false,
),
);
final size = ui.window.physicalSize / ui.window.devicePixelRatio;
const frequency = Duration(milliseconds: 50);
const numCircles = 299;
final red = Paint()..color = Colors.red;
final redStroke = Paint()
..color = Colors.red
..style = PaintingStyle.stroke;
final black = Paint()..color = Colors.black;
class Circle {
final Offset offset;
final double radius;
final Color color;
const Circle({this.offset, this.color = Colors.white, this.radius = 10});
}
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
Timer timer;
final circles = <Circle>[];
Offset force = Offset(1, 1);
HSLColor hslColor = HSLColor.fromColor(Colors.pink[100]);
final StreamController<List<Circle>> _circleStreamer =
StreamController<List<Circle>>.broadcast();
Stream<List<Circle>> get _circle$ => _circleStreamer.stream;
Color get color => hslColor.toColor();
Offset get randomPoint => size.topLeft(Offset.zero) * Random().nextDouble();
@override
void initState() {
timer = Timer.periodic(
frequency,
(t) {
if (circles.isEmpty)
_circleStreamer.add(
circles
..add(
Circle(
offset: randomPoint,
radius: 1,
color: hslColor.toColor(),
),
),
);
int count = 0;
while (count < 29) {
final p = // newPoint
size.bottomRight(Offset.zero) * 0.5 +
(size.bottomRight(Offset.zero) * 0.1).scale(
cos(circles.length / 59),
cos(circles.length / 99),
);
hslColor = hslColor.withHue((hslColor.hue + 0.2) % 360).withLightness(
min(1.0, .1 + sin(circles.length / 49).abs() / 10));
final r = // radius
size.width / 20 + (size.height / 30 * sin(circles.length / 79));
_circleStreamer
.add(circles..add(Circle(offset: p, radius: r, color: color)));
count++;
}
},
);
super.initState();
}
@override
void dispose() {
timer.cancel();
_circleStreamer.close();
super.dispose();
}
@override
Widget build(BuildContext context) => Stack(
children: [
StreamBuilder<List<Circle>>(
initialData: [],
stream: _circle$.map(
(event) => event.length > numCircles
? event
.getRange(event.length - numCircles, event.length)
.toList()
: event,
),
builder: (context, snapshot) => CustomPaint(
size: size,
painter: Painter(circles: snapshot.data),
),
),
],
);
}
class Painter extends CustomPainter {
List<Circle> circles;
Painter({this.circles});
@override
void paint(Canvas canvas, Size size) {
for (int i = 0; i < circles.length - 1; i++) {
final c = circles[i];
final hsl = HSLColor.fromColor(c.color);
final paint = Paint()
..color = c.color
..shader = ui.Gradient.linear(
c.offset,
c.offset + Offset(0, c.radius),
[
hsl.withLightness(max(0, min(1, hsl.lightness + 0.7))).toColor(),
c.color,
],
);
canvas
..drawCircle(c.offset, c.radius, paint)
..rotate(pi / 10800);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment