| import 'package:flutter/material.dart'; |
| import 'package:path_drawing/path_drawing.dart'; |
| |
| void main() => runApp(const MyApp()); |
| |
| class MyApp extends StatelessWidget { |
| const MyApp({Key? key}) : super(key: key); |
| |
| @override |
| Widget build(BuildContext context) { |
| return MaterialApp( |
| title: 'Flutter Demo', |
| theme: ThemeData( |
| primarySwatch: Colors.blue, |
| ), |
| home: const MyHomePage(title: 'Flutter Demo Home Page'), |
| ); |
| } |
| } |
| |
| class MyHomePage extends StatefulWidget { |
| const MyHomePage({Key? key, required this.title}) : super(key: key); |
| |
| final String title; |
| |
| @override |
| State<MyHomePage> createState() => _MyHomePageState(); |
| } |
| |
| class _MyHomePageState extends State<MyHomePage> { |
| late int index; |
| late double _trimPercent; |
| late PathTrimOrigin _trimOrigin; |
| |
| @override |
| void initState() { |
| super.initState(); |
| index = 0; |
| _trimPercent = 0.2; |
| _trimOrigin = PathTrimOrigin.begin; |
| } |
| |
| String get currPath => paths[index]; |
| |
| void nextPath() { |
| setState(() => index = index >= paths.length - 1 ? 0 : index + 1); |
| } |
| |
| void prevPath() { |
| setState(() => index = index == 0 ? paths.length - 1 : index - 1); |
| } |
| |
| void setTrimPercent(double value) { |
| setState(() { |
| _trimPercent = value; |
| }); |
| } |
| |
| void toggleTrimOrigin(PathTrimOrigin? value) { |
| setState(() { |
| switch (_trimOrigin) { |
| case PathTrimOrigin.begin: |
| _trimOrigin = PathTrimOrigin.end; |
| break; |
| case PathTrimOrigin.end: |
| _trimOrigin = PathTrimOrigin.begin; |
| break; |
| } |
| }); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return DefaultTabController( |
| length: 3, |
| child: Scaffold( |
| appBar: AppBar( |
| title: Text(widget.title), |
| bottom: const TabBar( |
| tabs: <Tab>[ |
| Tab(text: 'Path Trim'), |
| Tab(text: 'Path Dash'), |
| Tab(text: 'Path Parse'), |
| ], |
| ), |
| ), |
| body: TabBarView( |
| children: <Widget>[ |
| Stack( |
| children: <Widget>[ |
| CustomPaint( |
| painter: TrimPathPainter(_trimPercent, _trimOrigin)), |
| Align( |
| alignment: Alignment.bottomCenter, |
| child: Column( |
| mainAxisAlignment: MainAxisAlignment.end, |
| children: <Widget>[ |
| Slider( |
| value: _trimPercent, |
| onChanged: (double value) => setTrimPercent(value), |
| ), |
| RadioListTile<PathTrimOrigin>( |
| title: Text(PathTrimOrigin.begin.toString()), |
| value: PathTrimOrigin.begin, |
| groupValue: _trimOrigin, |
| onChanged: toggleTrimOrigin, |
| ), |
| RadioListTile<PathTrimOrigin>( |
| title: Text(PathTrimOrigin.end.toString()), |
| value: PathTrimOrigin.end, |
| groupValue: _trimOrigin, |
| onChanged: toggleTrimOrigin, |
| ), |
| ], |
| ), |
| ), |
| ], |
| ), |
| CustomPaint(painter: DashPathPainter()), |
| Stack( |
| children: <Widget>[ |
| CustomPaint(painter: PathTestPainter(currPath)), |
| GestureDetector( |
| onTap: nextPath, |
| ), |
| ], |
| ), |
| ], |
| ), |
| ), |
| ); |
| } |
| } |
| |
| const List<String> paths = <String>[ |
| 'm18 11.8a.41.41 0 0 1 .24.08l.59.43h.05.72a.4.4 0 0 1 .39.28l.22.69a.08.08 0 0 0 0 0l.58.43a.41.41 0 0 1 .15.45l-.22.68a.09.09 0 0 0 0 .07l.22.68a.4.4 0 0 1 -.15.46l-.58.42a.1.1 0 0 0 0 0l-.22.68a.41.41 0 0 1 -.38.29h-.79l-.58.43a.41.41 0 0 1 -.24.08.46.46 0 0 1 -.24-.08l-.58-.43h-.06-.72a.41.41 0 0 1 -.39-.28l-.22-.68a.1.1 0 0 0 0 0l-.58-.43a.42.42 0 0 1 -.15-.46l.23-.67v-.02l-.29-.68a.43.43 0 0 1 .15-.46l.58-.42a.1.1 0 0 0 0-.05l.27-.69a.42.42 0 0 1 .39-.28h.78l.58-.43a.43.43 0 0 1 .25-.09m0-1a1.37 1.37 0 0 0 -.83.27l-.34.25h-.43a1.42 1.42 0 0 0 -1.34 1l-.13.4-.35.25a1.42 1.42 0 0 0 -.51 1.58l.13.4-.13.4a1.39 1.39 0 0 0 .52 1.59l.34.25.13.4a1.41 1.41 0 0 0 1.34 1h.43l.34.26a1.44 1.44 0 0 0 .83.27 1.38 1.38 0 0 0 .83-.28l.35-.24h.43a1.4 1.4 0 0 0 1.33-1l.13-.4.35-.26a1.39 1.39 0 0 0 .51-1.57l-.13-.4.13-.41a1.4 1.4 0 0 0 -.51-1.56l-.35-.25-.13-.41a1.4 1.4 0 0 0 -1.34-1h-.42l-.34-.26a1.43 1.43 0 0 0 -.84-.28z', |
| '''M 15 15.5 A 0.5 1.5 0 1 1 14,15.5 A 0.5 1.5 0 1 1 15 15.5 z''', |
| 'M100,200 L3,4', |
| 'M100,200 l3,4', |
| 'M100,200 H3', |
| 'M100,200 h3', |
| 'M100,200 V3', |
| 'M100,200 v3', |
| 'M100,200 C3,4,5,6,7,8', |
| 'M100,200 c3,4,5,6,7,8', |
| 'M100,200 S3,4,5,6', |
| 'M100,200 s3,4,5,6', |
| 'M100,200 Q3,4,5,6', |
| 'M100,200 q3,4,5,6', |
| 'M100,200 T3,4', |
| 'M100,200 t3,4', |
| 'M100,200 A3,4,5,0,0,6,7', |
| 'M100,200 A3,4,5,1,0,6,7', |
| 'M100,200 A3,4,5,0,1,6,7', |
| 'M100,200 A3,4,5,1,1,6,7', |
| 'M100,200 a3,4,5,0,0,6,7', |
| 'M100,200 a3,4,5,0,1,6,7', |
| 'M100,200 a3,4,5,1,0,6,7', |
| 'M100,200 a3,4,5,1,1,6,7', |
| 'M100,200 a3,4,5,006,7', |
| 'M100,200 a3,4,5,016,7', |
| 'M100,200 a3,4,5,106,7', |
| 'M100,200 a3,4,5,116,7', |
| '''M19.0281,19.40466 20.7195,19.40466 20.7195,15.71439 24.11486,15.71439 24.11486,14.36762 20.7195,14.36762 |
| 20.7195,11.68641 24.74134,11.68641 24.74134,10.34618 19.0281,10.34618 z''', |
| 'M100,200 a0,4,5,0,0,10,0 a4,0,5,0,0,0,10 a0,0,5,0,0,-10,0 z', |
| 'M.1 .2 L.3 .4 .5 .6', |
| 'M1,1h2,3', |
| 'M1,1H2,3', |
| 'M1,1v2,3', |
| 'M1,1V2,3', |
| 'M1,1c2,3 4,5 6,7 8,9 10,11 12,13', |
| 'M1,1C2,3 4,5 6,7 8,9 10,11 12,13', |
| 'M1,1s2,3 4,5 6,7 8,9', |
| 'M1,1S2,3 4,5 6,7 8,9', |
| 'M1,1q2,3 4,5 6,7 8,9', |
| 'M1,1Q2,3 4,5 6,7 8,9', |
| 'M1,1t2,3 4,5', |
| 'M1,1T2,3 4,5', |
| 'M1,1a2,3,4,0,0,5,6 7,8,9,0,0,10,11', |
| 'M1,1A2,3,4,0,0,5,6 7,8,9,0,0,10,11', |
| ]; |
| |
| final Paint black = Paint() |
| ..color = Colors.black |
| ..strokeWidth = 1.0 |
| ..style = PaintingStyle.stroke; |
| |
| class TrimPathPainter extends CustomPainter { |
| TrimPathPainter(this.percent, this.origin); |
| |
| final double percent; |
| final PathTrimOrigin origin; |
| |
| final Path p = Path() |
| ..moveTo(10.0, 10.0) |
| ..lineTo(100.0, 100.0) |
| ..quadraticBezierTo(125.0, 20.0, 200.0, 100.0); |
| |
| @override |
| bool shouldRepaint(TrimPathPainter oldDelegate) => |
| oldDelegate.percent != percent; |
| |
| @override |
| void paint(Canvas canvas, Size size) { |
| canvas.drawPath(trimPath(p, percent, origin: origin), black); |
| } |
| } |
| |
| class DashPathPainter extends CustomPainter { |
| final Path p = Path() |
| ..moveTo(10.0, 10.0) |
| ..lineTo(100.0, 100.0) |
| ..quadraticBezierTo(125.0, 20.0, 200.0, 100.0) |
| ..addRect(const Rect.fromLTWH(0.0, 0.0, 50.0, 50.0)); |
| |
| @override |
| bool shouldRepaint(DashPathPainter oldDelegate) => true; |
| |
| @override |
| void paint(Canvas canvas, Size size) { |
| canvas.drawPath( |
| dashPath( |
| p, |
| dashArray: CircularIntervalList<double>( |
| <double>[5.0, 2.5], |
| ), |
| ), |
| black); |
| } |
| } |
| |
| class PathTestPainter extends CustomPainter { |
| PathTestPainter(String path) : p = parseSvgPathData(path); |
| |
| final Path p; |
| |
| @override |
| bool shouldRepaint(PathTestPainter oldDelegate) => true; |
| |
| @override |
| void paint(Canvas canvas, Size size) { |
| canvas.drawPath(p, black); |
| } |
| } |