Last active
November 9, 2022 14:37
-
-
Save iapicca/5fc8d8f465bfc2c2fcf9385e45788bb6 to your computer and use it in GitHub Desktop.
issue_28814 (b)
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 PathWrapperX on Path { | |
| PathWrapper wrap() => PathWrapper(this); | |
| } | |
| class PathWrapper { | |
| final Path path; | |
| PathWrapper(this.path) : hashCode = path.hashCode; | |
| @override | |
| bool operator ==(Object other) { | |
| if (other is! PathWrapper) { | |
| return false; | |
| } | |
| debugPrint('new hashcode: ${other.hashCode}' ' ' 'old hashcode: $hashCode'); | |
| return hashCode == other.hashCode; | |
| } | |
| @override | |
| final int hashCode; | |
| } | |
| extension PathFromSizeX on Size { | |
| Path path(double c) => Path() | |
| ..moveTo(0, height * .5) | |
| ..quadraticBezierTo( | |
| width * c, | |
| height, | |
| width, | |
| height * c, | |
| ); | |
| } | |
| final path = Size.zero.path(0).hashCode; | |
| 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; | |
| late final ValueNotifier<PathWrapper> _pathWrapper; | |
| void _coefficientListener() => _pathWrapper.value = _getPathWrapper(); | |
| PathWrapper _getPathWrapper() => | |
| widget.size.path(_pathCoefficient.value).wrap(); | |
| void _increaseDotCount() => _dotCount.value++; | |
| void _updatePathCx() => _pathCoefficient.value += .3; | |
| @override | |
| void initState() { | |
| _dotCount = ValueNotifier(0); | |
| _pathCoefficient = ValueNotifier(1)..addListener((_coefficientListener)); | |
| _pathWrapper = ValueNotifier(_getPathWrapper()); | |
| super.initState(); | |
| } | |
| @override | |
| void dispose() { | |
| _dotCount.dispose(); | |
| _pathCoefficient | |
| ..removeListener(_coefficientListener) | |
| ..dispose(); | |
| _pathWrapper.dispose(); | |
| super.dispose(); | |
| } | |
| @override | |
| Widget build(BuildContext context) => Scaffold( | |
| body: Column( | |
| mainAxisAlignment: MainAxisAlignment.center, | |
| children: [ | |
| ValueListenableBuilder<PathWrapper>( | |
| valueListenable: _pathWrapper, | |
| builder: (context, pathWrapper, child) => | |
| ValueListenableBuilder<int>( | |
| valueListenable: _dotCount, | |
| builder: (context, dotCount, child) => CustomPaint( | |
| size: widget.size, | |
| painter: MyCustomPainter( | |
| pathWrapper: pathWrapper, | |
| 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 PathWrapper pathWrapper; | |
| final int dots; | |
| final Color color; | |
| final double pathStrokeWidth; | |
| final double dotsStrokeWidth; | |
| const MyCustomPainter({ | |
| required this.pathWrapper, | |
| required this.dots, | |
| this.color = Colors.red, | |
| this.pathStrokeWidth = .8, | |
| this.dotsStrokeWidth = 4, | |
| }); | |
| @override | |
| void paint(Canvas canvas, Size size) { | |
| canvas.drawPath( | |
| pathWrapper.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) { | |
| final value = oldDelegate.pathWrapper != pathWrapper; | |
| debugPrint('should repaint: $value'); | |
| return value; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment