Last active
November 9, 2022 14:08
-
-
Save iapicca/b75eefb23009b68966a1dce0e73465d8 to your computer and use it in GitHub Desktop.
issue_28814
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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