├── .gitignore ├── .metadata ├── CHANGELOG.md ├── CODEOWNERS ├── LICENSE ├── README.md ├── example └── main.dart ├── lib ├── dash_decoration.dart └── dash_painter.dart ├── pubspec.lock └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/app.flx 64 | **/ios/Flutter/app.zip 65 | **/ios/Flutter/flutter_assets/ 66 | **/ios/Flutter/flutter_export_environment.sh 67 | **/ios/ServiceDefinitions.json 68 | **/ios/Runner/GeneratedPluginRegistrant.* 69 | 70 | # Exceptions to above rules. 71 | !**/ios/**/default.mode1v3 72 | !**/ios/**/default.mode2v3 73 | !**/ios/**/default.pbxuser 74 | !**/ios/**/default.perspectivev3 75 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1d9032c7e1d867f071f2277eb1673e8f9b0274e3 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1] - TODO: Add release date. 2 | 3 | * TODO: Describe initial release. 4 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @toly1994328 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 张风捷特烈(toly) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dash_painter 2 | 3 | a package for flutter canvas paint dash line path easily. 4 | 5 | #### 1. `DashPainter` 如何使用 6 | 7 | `DashPainter` 只负责对 `路径 Path` 的虚线化绘制,不承担组件职能。 8 | 一般用在拥有 `Canvas` 对象的回调方法中,比如自定义的 `CustomPainter`、`Decoration`。 9 | 具体使用案例见 demo 10 | 11 | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210509210035976.png) 12 | 13 | ```dart 14 | const DashPainter(span: 4, step: 9).paint(canvas, path, paint); 15 | ``` 16 | 17 | 对于所有的路径都是使用的,如下的 `圆角矩形` 和 `圆形`; 18 | 19 | | 圆角矩形 | 圆形 | 20 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 21 | | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210510070700102.png) | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210509211922128.png) | 22 | 23 | --- 24 | 25 | #### 2. 点划线的使用 26 | 27 | 28 | 除了虚线,还可以绘制`点划线` , `pointCount` 和 `pointWidth`两个属性,分别表示`点划线数`和`点划线长`。 29 | 30 | ```dart 31 | const DashPainter( 32 | span: 4, // 空格长 33 | step: 10, // 实线长 34 | pointCount: 2, // 点划线个数 35 | pointWidth: 2 // 点划线长 36 | ).paint(canvas, path, paint); 37 | ``` 38 | 39 | - `单点划线`: 40 | 41 | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210510070923020.png) 42 | 43 | - `双点划线`: 44 | 45 | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210510071049769.png) 46 | 47 | - `三点划线`: 48 | 49 | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210510071131986.png) 50 | 51 | --- 52 | 53 | `点画线圆`: 54 | 55 | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210510072143441.png) 56 | 57 | --- 58 | 59 | #### `DashPainter` 60 | 61 | 可能很多人不会自定义画板自己绘制,或只想简单地使用。其实除了 `CustomPainter` 还有其他地方有 `canvas`。比如 `Decoration` 。 62 | 这里提供了 `DashDecoration` 的装饰,方便使用。如下实现一个`渐变的单点画线圆角虚线框`。 63 | 64 | ![](https://gitee.com/toly1994/toly_blog_pic/raw/master/image-20210510091605411.png) 65 | 66 | ```dart 67 | Container( 68 | width: 100, 69 | height: 100, 70 | decoration: DashDecoration( 71 | pointWidth: 2, 72 | step: 5, 73 | pointCount: 1, 74 | radius: Radius.circular(15), 75 | gradient: SweepGradient(colors: [ 76 | Colors.blue, 77 | Colors.red, 78 | Colors.yellow, 79 | Colors.green 80 | ])), 81 | child: Icon( 82 | Icons.add, 83 | color: Colors.orangeAccent, 84 | size: 40, 85 | ), 86 | ), 87 | ``` -------------------------------------------------------------------------------- /example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:dash_painter/dash_painter.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | 5 | void main() => runApp(MyApp()); 6 | 7 | class MyApp extends StatelessWidget { 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return MaterialApp( 12 | debugShowCheckedModeBanner: false, 13 | title: 'Flutter Demo', 14 | theme: ThemeData( 15 | primarySwatch: Colors.blue, 16 | ), 17 | home: Scaffold( 18 | body: Center( 19 | child: CustomPaint( 20 | size: Size(200,200), 21 | painter: TolyPainter()), 22 | ), 23 | ), 24 | ); 25 | } 26 | } 27 | 28 | class TolyPainter extends CustomPainter { 29 | 30 | @override 31 | void paint(Canvas canvas, Size size) { 32 | canvas.translate(size.width / 2, size.height / 2); 33 | 34 | Paint paint = Paint() 35 | ..style = PaintingStyle.stroke 36 | ..color = Colors.orangeAccent 37 | ..strokeWidth = 1; 38 | 39 | final Path path = Path(); 40 | path.moveTo(-200, 0); 41 | path.lineTo(200, 0); 42 | path.moveTo(0, -200); 43 | path.lineTo(0, 200); 44 | 45 | path.addOval(Rect.fromCircle(center: Offset.zero, radius: 80)); 46 | path.addRRect(RRect.fromRectAndRadius( 47 | Rect.fromCircle(center: Offset.zero, radius: 100), 48 | Radius.circular(20), 49 | )); 50 | const DashPainter(span: 4, step: 9).paint(canvas, path, paint); 51 | } 52 | 53 | @override 54 | bool shouldRepaint(covariant TolyPainter oldDelegate) => false; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /lib/dash_decoration.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'dash_painter.dart'; 4 | 5 | class DashDecoration extends Decoration { 6 | final Gradient? gradient; 7 | 8 | final Color? color; 9 | final double step; 10 | final double span; 11 | final int pointCount; 12 | final double? pointWidth; 13 | final Radius? radius; 14 | final double strokeWidth; 15 | 16 | DashDecoration( 17 | {this.gradient, 18 | this.color, 19 | this.step = 2, 20 | this.strokeWidth =1 , 21 | this.span = 2, 22 | this.pointCount = 0, 23 | this.pointWidth, 24 | this.radius}); 25 | 26 | @override 27 | BoxPainter createBoxPainter([VoidCallback? onChanged]) => DashBoxPainter(this); 28 | } 29 | 30 | class DashBoxPainter extends BoxPainter { 31 | final DashDecoration _decoration; 32 | 33 | DashBoxPainter(this._decoration); 34 | 35 | @override 36 | void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { 37 | if(configuration.size==null){ 38 | return; 39 | } 40 | 41 | Radius radius = _decoration.radius ?? Radius.zero; 42 | canvas.save(); 43 | final Paint paint = Paint() 44 | ..style = PaintingStyle.stroke 45 | ..color = Colors.orangeAccent 46 | ..strokeWidth = _decoration.strokeWidth; 47 | final Path path = Path(); 48 | 49 | canvas.translate( 50 | offset.dx + configuration.size!.width / 2, 51 | offset.dy + configuration.size!.height / 2, 52 | ); 53 | 54 | final Rect zone = Rect.fromCenter( 55 | center: Offset.zero, 56 | width: configuration.size!.width, 57 | height: configuration.size!.height, 58 | ); 59 | 60 | if (_decoration.color != null) { 61 | final Paint rectPaint = Paint()..color = _decoration.color!; 62 | canvas.drawRRect( 63 | RRect.fromRectAndRadius(zone, radius), rectPaint); 64 | } 65 | 66 | path.addRRect(RRect.fromRectAndRadius( 67 | zone, 68 | radius, 69 | )); 70 | 71 | if (_decoration.gradient != null) { 72 | paint.shader = _decoration.gradient!.createShader(zone); 73 | } 74 | 75 | DashPainter( 76 | span: _decoration.span, 77 | step: _decoration.step, 78 | pointCount: _decoration.pointCount, 79 | pointWidth: _decoration.pointWidth, 80 | ).paint(canvas, path, paint); 81 | canvas.restore(); 82 | } 83 | } -------------------------------------------------------------------------------- /lib/dash_painter.dart: -------------------------------------------------------------------------------- 1 | library dash_painter; 2 | 3 | import 'dart:ui'; 4 | 5 | // [step] the length of solid line 每段实线长 6 | // [span] the space of each solid line 每段空格线长 7 | // [pointCount] the point count of dash line 点划线的点数 8 | // [pointWidth] the point width of dash line 点划线的点划长 9 | 10 | class DashPainter { 11 | const DashPainter({ 12 | this.step = 2, 13 | this.span = 2, 14 | this.pointCount = 0, 15 | this.pointWidth, 16 | }); 17 | 18 | final double step; 19 | final double span; 20 | final int pointCount; 21 | final double? pointWidth; 22 | 23 | void paint(Canvas canvas, Path path, Paint paint) { 24 | final PathMetrics pms = path.computeMetrics(); 25 | final double pointLineLength = pointWidth ?? paint.strokeWidth; 26 | final double partLength = 27 | step + span * (pointCount + 1) + pointCount * pointLineLength; 28 | 29 | pms.forEach((PathMetric pm) { 30 | final int count = pm.length ~/ partLength; 31 | for (int i = 0; i < count; i++) { 32 | canvas.drawPath( 33 | pm.extractPath(partLength * i, partLength * i + step), paint,); 34 | for (int j = 1; j <= pointCount; j++) { 35 | final start = 36 | partLength * i + step + span * j + pointLineLength * (j - 1); 37 | canvas.drawPath( 38 | pm.extractPath(start, start + pointLineLength), 39 | paint, 40 | ); 41 | } 42 | } 43 | final double tail = pm.length % partLength; 44 | canvas.drawPath(pm.extractPath(pm.length - tail, pm.length), paint); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.flutter-io.cn" 9 | source: hosted 10 | version: "2.5.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.flutter-io.cn" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.flutter-io.cn" 23 | source: hosted 24 | version: "1.1.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.flutter-io.cn" 30 | source: hosted 31 | version: "1.2.0" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.flutter-io.cn" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.flutter-io.cn" 44 | source: hosted 45 | version: "1.15.0" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.flutter-io.cn" 51 | source: hosted 52 | version: "1.2.0" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_test: 59 | dependency: "direct dev" 60 | description: flutter 61 | source: sdk 62 | version: "0.0.0" 63 | matcher: 64 | dependency: transitive 65 | description: 66 | name: matcher 67 | url: "https://pub.flutter-io.cn" 68 | source: hosted 69 | version: "0.12.10" 70 | meta: 71 | dependency: transitive 72 | description: 73 | name: meta 74 | url: "https://pub.flutter-io.cn" 75 | source: hosted 76 | version: "1.3.0" 77 | path: 78 | dependency: transitive 79 | description: 80 | name: path 81 | url: "https://pub.flutter-io.cn" 82 | source: hosted 83 | version: "1.8.0" 84 | sky_engine: 85 | dependency: transitive 86 | description: flutter 87 | source: sdk 88 | version: "0.0.99" 89 | source_span: 90 | dependency: transitive 91 | description: 92 | name: source_span 93 | url: "https://pub.flutter-io.cn" 94 | source: hosted 95 | version: "1.8.0" 96 | stack_trace: 97 | dependency: transitive 98 | description: 99 | name: stack_trace 100 | url: "https://pub.flutter-io.cn" 101 | source: hosted 102 | version: "1.10.0" 103 | stream_channel: 104 | dependency: transitive 105 | description: 106 | name: stream_channel 107 | url: "https://pub.flutter-io.cn" 108 | source: hosted 109 | version: "2.1.0" 110 | string_scanner: 111 | dependency: transitive 112 | description: 113 | name: string_scanner 114 | url: "https://pub.flutter-io.cn" 115 | source: hosted 116 | version: "1.1.0" 117 | term_glyph: 118 | dependency: transitive 119 | description: 120 | name: term_glyph 121 | url: "https://pub.flutter-io.cn" 122 | source: hosted 123 | version: "1.2.0" 124 | test_api: 125 | dependency: transitive 126 | description: 127 | name: test_api 128 | url: "https://pub.flutter-io.cn" 129 | source: hosted 130 | version: "0.2.19" 131 | typed_data: 132 | dependency: transitive 133 | description: 134 | name: typed_data 135 | url: "https://pub.flutter-io.cn" 136 | source: hosted 137 | version: "1.3.0" 138 | vector_math: 139 | dependency: transitive 140 | description: 141 | name: vector_math 142 | url: "https://pub.flutter-io.cn" 143 | source: hosted 144 | version: "2.1.0" 145 | sdks: 146 | dart: ">=2.12.0 <3.0.0" 147 | flutter: ">=1.17.0" 148 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dash_painter 2 | description: a package for flutter canvas paint dash line path easily. 3 | version: 1.0.2 4 | author: 张风捷特烈<1981462002@qq.com> 5 | homepage: https://juejin.cn/user/149189281194766/posts 6 | 7 | environment: 8 | sdk: ">=2.12.0 <3.0.0" 9 | flutter: ">=1.17.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | 19 | # For information on the generic Dart part of this file, see the 20 | # following page: https://dart.dev/tools/pub/pubspec 21 | 22 | # The following section is specific to Flutter. 23 | flutter: 24 | 25 | # To add assets to your package, add an assets section, like this: 26 | # assets: 27 | # - images/a_dot_burr.jpeg 28 | # - images/a_dot_ham.jpeg 29 | # 30 | # For details regarding assets in packages, see 31 | # https://flutter.dev/assets-and-images/#from-packages 32 | # 33 | # An image asset can refer to one or more resolution-specific "variants", see 34 | # https://flutter.dev/assets-and-images/#resolution-aware. 35 | 36 | # To add custom fonts to your package, add a fonts section here, 37 | # in this "flutter" section. Each entry in this list should have a 38 | # "family" key with the font family name, and a "fonts" key with a 39 | # list giving the asset and other descriptors for the font. For 40 | # example: 41 | # fonts: 42 | # - family: Schyler 43 | # fonts: 44 | # - asset: fonts/Schyler-Regular.ttf 45 | # - asset: fonts/Schyler-Italic.ttf 46 | # style: italic 47 | # - family: Trajan Pro 48 | # fonts: 49 | # - asset: fonts/TrajanPro.ttf 50 | # - asset: fonts/TrajanPro_Bold.ttf 51 | # weight: 700 52 | # 53 | # For details regarding fonts in packages, see 54 | # https://flutter.dev/custom-fonts/#from-packages 55 | --------------------------------------------------------------------------------