Skip to content

Instantly share code, notes, and snippets.

@iapicca
Last active November 9, 2022 14:08
Show Gist options
  • Select an option

  • Save iapicca/b75eefb23009b68966a1dce0e73465d8 to your computer and use it in GitHub Desktop.

Select an option

Save iapicca/b75eefb23009b68966a1dce0e73465d8 to your computer and use it in GitHub Desktop.
issue_28814
import 'package:flutter/material.dart';
import 'dart:math' show Random;
import 'dart:ui' as ui;
extension PathFromSizeX on Size {
Path path(double c) => Path()
..moveTo(0, height * .5)
..quadraticBezierTo(
width * c,
height,
width,
height * c,
);
}
extension RandomX on Size {
Offset randomOffset() => Offset(
Random().nextInt(width.truncate()).toDouble(),
Random().nextInt(height.truncate()).toDouble(),
);
}
void main() => runApp(const MaterialApp(home: MyHomePage()));
class MyHomePage extends StatefulWidget {
final Size size;
const MyHomePage({super.key, this.size = const Size(200, 400)});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late final ValueNotifier<int> _dotCount;
late final ValueNotifier<double> _pathCoefficient;
void _increaseDotCount() => _dotCount.value++;
void _updatePathCx() => _pathCoefficient.value += .3;
@override
void initState() {
_dotCount = ValueNotifier(0);
_pathCoefficient = ValueNotifier(1);
super.initState();
}
@override
void dispose() {
_dotCount.dispose();
_pathCoefficient.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ValueListenableBuilder<double>(
valueListenable: _pathCoefficient,
builder: (context, coefficient, child) =>
ValueListenableBuilder<int>(
valueListenable: _dotCount,
builder: (context, dotCount, child) => CustomPaint(
size: widget.size,
painter: MyCustomPainter(
path: widget.size.path(coefficient),
dots: dotCount,
),
),
),
),
TextButton(
onPressed: _increaseDotCount,
child: const Icon(Icons.plus_one),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: _updatePathCx,
child: const Icon(Icons.add),
),
);
}
class MyCustomPainter extends CustomPainter {
final Path path;
final int dots;
final Color color;
final double pathStrokeWidth;
final double dotsStrokeWidth;
const MyCustomPainter({
required this.path,
required this.dots,
this.color = Colors.red,
this.pathStrokeWidth = .8,
this.dotsStrokeWidth = 4,
});
@override
void paint(Canvas canvas, Size size) {
canvas.drawPath(
path,
Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = pathStrokeWidth,
);
canvas.drawPoints(
ui.PointMode.points,
[for (int i = 0; i < dots; ++i) size.randomOffset()],
Paint()
..color = Colors.black
..strokeWidth = dotsStrokeWidth
..strokeCap = StrokeCap.round,
);
}
@override
bool shouldRepaint(MyCustomPainter oldDelegate) => oldDelegate.path != path;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment