├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README_CN.md ├── example ├── .gitignore ├── assets │ └── icon_logo.png ├── lib │ ├── color.dart │ ├── main.dart │ └── part.dart └── pubspec.yaml ├── lib └── fdottedline.dart ├── pubspec.yaml └── test └── fdottedline_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .idea/ 10 | 11 | .metadata 12 | 13 | *.iml 14 | 15 | pubspec.lock 16 | 17 | 18 | android/ 19 | ios/ 20 | macos/ 21 | 22 | readme.py 23 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0 2 | 3 | - the first version 4 | 5 | ## 1.0.1 6 | 7 | - Correct the judgment condition added last 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020-present Fliggy Android Team . 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at following link. 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 |

fdottedline

8 | 9 | 10 |
11 | 12 |

Use the easiest way to create a dotted line view 👀!

13 | 14 |

[FDottedLine] provides developers with the ability to create dashed lines. It also supports creating a dashed border for a [Widget]. Support for controlling the thickness, spacing, and corners of the dotted border.

15 | 16 |

Author:Newton(coorchice.cb@alibaba-inc.com)

17 | 18 |

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |

47 |

48 | 49 |

50 | 51 |

52 | 53 | 54 | 55 |

56 | 57 | **English | [简体中文](https://github.com/Fliggy-Mobile/fdottedline/blob/master/README_CN.md)** 58 | 59 | > Like it? Please cast your **Star** 🥰 ! 60 | 61 | # ✨ Features 62 | 63 | - Supports dotted lines in both horizontal and vertical directions 64 | 65 | - Support to create dashed shapes 66 | 67 | - Provide super easy way to add dotted border to **Widget** 68 | 69 | - Support creating flexible dotted corner effects 70 | 71 | ## ⚙️ Parameter & Interface 72 | 73 | ### 🔩 FDottedLine param 74 | 75 | |Param|Type|Necessary|Default|desc| 76 | |---|---|:---:|---|---| 77 | |color|Color|false|`Colors.black`|Dotted line color| 78 | |height|double|false|null|height. If there is only [height] and no [width], you will get a dotted line in the vertical direction.If there are both [width] and [height], you will get a dotted border.| 79 | |width|double|false|null|width. If there is only [width] and no [height], you will get a dotted line in the horizontal direction.If there are both [width] and [height], you will get a dotted border.| 80 | |strokeWidth|double|false|1.0|The thickness of the dotted line| 81 | |dottedLength|double|false|5.0|The length of each small segment in the dotted line| 82 | |space|double|false|3.0|The distance between each segment in the dotted line| 83 | |corner|FDottedLineCorner|false|null|The corners of the dotted border. See [FDottedLineCorner] for details| 84 | |child|Widget|false|null|If [child] is set, [FDottedLine] will serve as the dotted border of [child].At this time, [width] and [height] will no longer be valid.| 85 | 86 | 87 | ## 📺 Demo 88 | 89 | ### 🔩 Horizontal Demo 90 | 91 | ![](https://gw.alicdn.com/tfs/TB1ClEbI5_1gK0jSZFqXXcpaXXa-360-340.png) 92 | 93 | ```dart 94 | FDottedLine( 95 | color: color, 96 | width: 160.0, 97 | strokeWidth: 2.0, 98 | dottedLength: 10.0, 99 | space: 2.0, 100 | ) 101 | ``` 102 | 103 | It is very simple to create a horizontal dotted line through **FDottedLine**. 104 | 105 | The developer only needs to set the `width` parameter, but not the `height` parameter, which is all the developer needs to do for this. 106 | 107 | If you want to control the thickness of the dotted line, set `strokeWidth`. 108 | 109 | Through the `dottedLength` and `space` parameters, developers can freely control the length of each small segment in the dotted line and the distance between them. 110 | 111 | ### ⛓ Vertical Demo 112 | 113 | ![](https://gw.alicdn.com/tfs/TB1_eVgXDM11u4jSZPxXXahcXXa-360-319.png) 114 | 115 | ```dart 116 | FDottedLine( 117 | color: color, 118 | height: 160.0, 119 | strokeWidth: 2.0, 120 | dottedLength: 10.0, 121 | space: 2.0, 122 | ) 123 | ``` 124 | 125 | If you want to create a dotted line in the vertical direction, it is also very simple. 126 | 127 | Developers only need to assign a value to `height` and leave `width` to be `null` or **0**. 128 | 129 | ### 🔹 Dotted Shape Demo 130 | 131 | ![](https://gw.alicdn.com/tfs/TB1q5Y_IVY7gK0jSZKzXXaikpXa-638-360.png) 132 | 133 | ```dart 134 | FDottedLine( 135 | color: Colors.lightBlue[600], 136 | height: 100.0, 137 | width: 50, 138 | strokeWidth: 2.0, 139 | dottedLength: 10.0, 140 | space: 2.0, 141 | ) 142 | ``` 143 | 144 | **FDottedLine** can not only create simple dotted lines 🌝. 145 | 146 | When developers assign values ​​to both width and height, they will be able to get a dotted rectangle! It's incredible. 147 | 148 | ### 🌏 Corner Demo 149 | 150 | ![](https://gw.alicdn.com/tfs/TB17TwjI8r0gK0jSZFnXXbRRXXa-629-360.png) 151 | 152 | ```dart 153 | FDottedLine( 154 | color: Colors.lightBlue[600], 155 | height: 70.0, 156 | width: 70.0, 157 | strokeWidth: 2.0, 158 | dottedLength: 10.0, 159 | space: 2.0, 160 | 161 | /// Set corner 162 | corner: FDottedLineCorner.all(50), 163 | ) 164 | ``` 165 | 166 | With **FDottedLine**, developers can even create corner effects of dashed rectangles. For example: dotted rounded rectangle, dotted round... 167 | 168 | ### 🧩 Child Demo 169 | 170 | ![](https://gw.alicdn.com/tfs/TB1aSZaI1H2gK0jSZFEXXcqMpXa-360-324.png) 171 | 172 | ```dart 173 | FDottedLine( 174 | color: color, 175 | strokeWidth: 2.0, 176 | dottedLength: 8.0, 177 | space: 3.0, 178 | corner: FDottedLineCorner.all(6.0), 179 | 180 | /// add widget 181 | child: Container( 182 | color: Colors.blue[100], 183 | width: 130, 184 | height: 70, 185 | alignment: Alignment.center, 186 | child: Text("0873"), 187 | ), 188 | ) 189 | ``` 190 | 191 | In the past, it was very difficult to add a dotted border to a **Widget**. 192 | 193 | Because the official did not provide us with a good solution. But now, **FDottedLine** makes things easier than ever. Developers only need to use their **Widget** as a child of **FDottedLine**. 194 | 195 | ![](https://gw.alicdn.com/tfs/TB12HoXIYr1gK0jSZR0XXbP8XXa-360-333.png) 196 | 197 | 198 | ```dart 199 | 200 | /// #1 201 | FDottedLine( 202 | color: color, 203 | strokeWidth: 2.0, 204 | dottedLength: 8.0, 205 | space: 3.0, 206 | corner: FDottedLineCorner.all(75.0), 207 | child: Container( 208 | width: 130, 209 | height: 130, 210 | alignment: Alignment.center, 211 | /// #2 212 | child: FDottedLine( 213 | color: color, 214 | strokeWidth: 2.0, 215 | dottedLength: 8.0, 216 | space: 3.0, 217 | corner: FDottedLineCorner.all(20.0), 218 | child: Container( 219 | width: 43.0, 220 | height: 43.0, 221 | color: Colors.grey[900], 222 | ), 223 | ), 224 | ), 225 | ) 226 | ``` 227 | 228 | This also means that through the nesting of **FDottedLine**, many super interesting views can be created. 229 | 230 | ### 💡 More Demo 231 | 232 | ![](https://gw.alicdn.com/tfs/TB17_wjI8r0gK0jSZFnXXbRRXXa-480-511.png) 233 | 234 | See what **FDottedLine** can do! 235 | 236 | When there is such a simple way to create a dotted line, developers can freely build more wonderful views. 237 | 238 | 239 | ![](https://gw.alicdn.com/tfs/TB1geStkIKfxu4jSZPfXXb3dXXa-720-227.gif) 240 | 241 | More about the application of **FDottedLine** , look forward to the exploration of developers 🔆. 242 | 243 | # 😃 How to use? 244 | 245 | Add dependencies in the project `pubspec.yaml` file: 246 | 247 | ## 🌐 pub dependency 248 | 249 | ``` 250 | dependencies: 251 | fdottedline: ^ 252 | ``` 253 | 254 | > ⚠️ Attention,please go to [**pub**] (https://pub.dev/packages/fdottedline) to get the latest version number of **FDottedLine** 255 | 256 | ## 🖥 Git dependency 257 | 258 | ``` 259 | dependencies: 260 | fdottedline: 261 | git: 262 | url: 'git@github.com:Fliggy-Mobile/fdottedline.git' 263 | ref: '' 264 | ``` 265 | 266 | > ⚠️ Attention,please refer to [**FDottedLine**] (https://github.com/Fliggy-Mobile/fdottedline) official project for branch number or tag. 267 | 268 | 269 | # 💡 License 270 | 271 | ``` 272 | Copyright 2020-present Fliggy Android Team . 273 | 274 | Licensed under the Apache License, Version 2.0 (the "License"); 275 | you may not use this file except in compliance with the License. 276 | You may obtain a copy of the License at following link. 277 | 278 | http://www.apache.org/licenses/LICENSE-2.0 279 | 280 | Unless required by applicable law or agreed to in writing, software 281 | distributed under the License is distributed on an "AS IS" BASIS, 282 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 283 | See the License for the specific language governing permissions and 284 | limitations under the License. 285 | 286 | ``` 287 | 288 | ### Like it? Please cast your [**Star**](https://github.com/Fliggy-Mobile/fdottedline) 🥰 ! 289 | 290 | 291 | --- 292 | 293 | # How to run Demo project? 294 | 295 | 1.**clone** project to local 296 | 297 | 2.Enter the project `example` directory and run the following command 298 | 299 | ``` 300 | flutter create . 301 | ``` 302 | 303 | 3.Run the demo in `example` 304 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 |

fdottedline

8 | 9 | 10 |
11 | 12 |

用最简单的方式来创建虚线视图吧 👀 !

13 | 14 |

[FDottedLine] 为开发者提供了创建虚线的能力。同时支持为一个 [Widget] 创建虚线边框。支持控制虚线的粗细,间距,以及虚线边框的边角。

15 | 16 |

主理人:纽特(coorchice.cb@alibaba-inc.com)

17 | 18 |

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |

47 |

48 | 49 |

50 | 51 | 52 |

53 | 54 | 55 | 56 |

57 | 58 | **[English](https://github.com/Fliggy-Mobile/fdottedline) | 简体中文** 59 | 60 | > 感觉还不错?请投出您的 **Star** 吧 🥰 ! 61 | 62 | # ✨ 特性 63 | 64 | - 同时支持水平、垂直两个方向的虚线 65 | 66 | - 支持创建虚线形状 67 | 68 | - 提供超简单的方式为 **Widget** 添加虚线边框 69 | 70 | - 支持创建灵活的虚线边角效果 71 | 72 | # 🛠 使用指南 73 | 74 | 75 | ## ⚙️ 参数 & 接口 76 | 77 | ### 🔩 FDottedLine 参数 78 | 79 | |参数|类型|必要|默认值|说明| 80 | |---|---|:---:|---|---| 81 | |color|Color|false|`Colors.black`|虚线颜色| 82 | |height|double|false|null|高。如果只有 [height],而没有 [width],将获得一个垂直方向的虚线。如果同时有 [width] 和 [height],将获得一个虚线边框。| 83 | |width|double|false|null|宽。如果只有 [width],而没有 [height],将获得一个水平方向的虚线。如果同时有 [width] 和 [height],将获得一个虚线边框。| 84 | |strokeWidth|double|false|1.0|虚线的厚度| 85 | |dottedLength|double|false|5.0|虚线中每一小段的长| 86 | |space|double|false|3.0|虚线中每段间的距离| 87 | |corner|FDottedLineCorner|false|null|虚线边框的边角。详见 [FDottedLineCorner]| 88 | |child|Widget|false|null|如果设置了 [child],[FDottedLine] 将会作为 [child] 的虚线边框。此时,[width] 和 [height] 将不再有效。| 89 | 90 | 91 | ## 📺 使用示例 92 | 93 | ### 🔩 Horizontal Demo 94 | 95 | ![](https://gw.alicdn.com/tfs/TB1ClEbI5_1gK0jSZFqXXcpaXXa-360-340.png) 96 | 97 | ```dart 98 | FDottedLine( 99 | color: color, 100 | width: 160.0, 101 | strokeWidth: 2.0, 102 | dottedLength: 10.0, 103 | space: 2.0, 104 | ) 105 | ``` 106 | 107 | 通过 **FDottedLine** 创建一个水平虚线,异常简单。 108 | 109 | 开发者只需要设置 `width` 参数,而不设置 `height` 参数,这就是开发者为此所要做的所有事情。 110 | 111 | 如果想要控制虚线的厚度,设置 `strokeWidth` 就好了。 112 | 113 | 通过 `dottedLength` 和 `space` 参数,开发者可以自由控制虚线中每一小段的长度,以及它们之间的距离。 114 | 115 | ### ⛓ Vertical Demo 116 | 117 | ![](https://gw.alicdn.com/tfs/TB1_eVgXDM11u4jSZPxXXahcXXa-360-319.png) 118 | 119 | ```dart 120 | FDottedLine( 121 | color: color, 122 | height: 160.0, 123 | strokeWidth: 2.0, 124 | dottedLength: 10.0, 125 | space: 2.0, 126 | ) 127 | ``` 128 | 129 | 如果想要创建垂直方向的虚线,同样很简单。 130 | 131 | 开发者只需要给 `height` 赋值,而让 `width` 保持为 `null` 或者 **0** 即可。 132 | 133 | ### 🔹 Dotted Shape Demo 134 | 135 | ![](https://gw.alicdn.com/tfs/TB1q5Y_IVY7gK0jSZKzXXaikpXa-638-360.png) 136 | 137 | ```dart 138 | FDottedLine( 139 | color: Colors.lightBlue[600], 140 | height: 100.0, 141 | width: 50, 142 | strokeWidth: 2.0, 143 | dottedLength: 10.0, 144 | space: 2.0, 145 | ) 146 | ``` 147 | 148 | **FDottedLine** 可不仅仅只能创建简单的虚线 🌝。 149 | 150 | 当开发者同时为 `width` 和 `height` 都赋值时,将能够获得一个虚线矩形!不可思议吧。 151 | 152 | ### 🌏 Corner Demo 153 | 154 | ![](https://gw.alicdn.com/tfs/TB17TwjI8r0gK0jSZFnXXbRRXXa-629-360.png) 155 | 156 | ```dart 157 | FDottedLine( 158 | color: Colors.lightBlue[600], 159 | height: 70.0, 160 | width: 70.0, 161 | strokeWidth: 2.0, 162 | dottedLength: 10.0, 163 | space: 2.0, 164 | 165 | /// 设置边角 166 | corner: FDottedLineCorner.all(50), 167 | ) 168 | ``` 169 | 170 | 通过 **FDottedLine** ,开发者甚至可以创建出虚线矩形的边角效果。比如:虚线圆角矩形,虚线圆形.. 171 | 172 | ### 🧩 Child Demo 173 | 174 | ![](https://gw.alicdn.com/tfs/TB1aSZaI1H2gK0jSZFEXXcqMpXa-360-324.png) 175 | 176 | ```dart 177 | FDottedLine( 178 | color: color, 179 | strokeWidth: 2.0, 180 | dottedLength: 8.0, 181 | space: 3.0, 182 | corner: FDottedLineCorner.all(6.0), 183 | 184 | /// 添加 widget 185 | child: Container( 186 | color: Colors.blue[100], 187 | width: 130, 188 | height: 70, 189 | alignment: Alignment.center, 190 | child: Text("0873"), 191 | ), 192 | ) 193 | ``` 194 | 195 | 在过去,想要为一个 **Widget** 添加虚线边框,是件十分困难的事情。因为官方没有为我们提供很好的解决方案。 196 | 197 | 但是现在, **FDottedLine** 让事情变得空前简单。开发者只需要将自己的 **Widget** 作为 **FDottedLine** 的 `child` 就行。 198 | 199 | ![](https://gw.alicdn.com/tfs/TB12HoXIYr1gK0jSZR0XXbP8XXa-360-333.png) 200 | 201 | 202 | ```dart 203 | 204 | /// #1 205 | FDottedLine( 206 | color: color, 207 | strokeWidth: 2.0, 208 | dottedLength: 8.0, 209 | space: 3.0, 210 | corner: FDottedLineCorner.all(75.0), 211 | child: Container( 212 | width: 130, 213 | height: 130, 214 | alignment: Alignment.center, 215 | /// #2 216 | child: FDottedLine( 217 | color: color, 218 | strokeWidth: 2.0, 219 | dottedLength: 8.0, 220 | space: 3.0, 221 | corner: FDottedLineCorner.all(20.0), 222 | child: Container( 223 | width: 43.0, 224 | height: 43.0, 225 | color: Colors.grey[900], 226 | ), 227 | ), 228 | ), 229 | ) 230 | ``` 231 | 232 | 这也就意味着,通过 **FDottedLine** 的嵌套,可以创建出很多超级有趣的视图。 233 | 234 | ### 💡 More Demo 235 | 236 | ![](https://gw.alicdn.com/tfs/TB17_wjI8r0gK0jSZFnXXbRRXXa-480-511.png) 237 | 238 | 看看 **FDottedLine** 都能干些什么! 239 | 240 | 当拥有了如此简单的方式创建虚线,开发者可以自由构建出更多精彩绝伦的视图。 241 | 242 | ![](https://gw.alicdn.com/tfs/TB1geStkIKfxu4jSZPfXXb3dXXa-720-227.gif) 243 | 244 | 更多关于 **FDottedLine** 的应用,期待开发者们的探索 🔆。 245 | 246 | 247 | # 😃 如何使用? 248 | 249 | 在项目 `pubspec.yaml` 文件中添加依赖: 250 | 251 | ## 🌐 pub 依赖方式 252 | 253 | ``` 254 | dependencies: 255 | fdottedline: ^<版本号> 256 | ``` 257 | 258 | > ⚠️ 注意,请到 [**pub**](https://pub.dev/packages/fdottedline) 获取 **FDottedLine** 最新版本号 259 | 260 | ## 🖥 git 依赖方式 261 | 262 | ``` 263 | dependencies: 264 | fdottedline: 265 | git: 266 | url: 'git@github.com:Fliggy-Mobile/fdottedline.git' 267 | ref: '<分支号 或 tag>' 268 | ``` 269 | 270 | 271 | > ⚠️ 注意,分支号 或 tag 请以 [**FDottedLine**](https://github.com/Fliggy-Mobile/fdottedline) 官方项目为准。 272 | 273 | 274 | # 💡 License 275 | 276 | ``` 277 | Copyright 2020-present Fliggy Android Team . 278 | 279 | Licensed under the Apache License, Version 2.0 (the "License"); 280 | you may not use this file except in compliance with the License. 281 | You may obtain a copy of the License at following link. 282 | 283 | http://www.apache.org/licenses/LICENSE-2.0 284 | 285 | Unless required by applicable law or agreed to in writing, software 286 | distributed under the License is distributed on an "AS IS" BASIS, 287 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 288 | See the License for the specific language governing permissions and 289 | limitations under the License. 290 | 291 | ``` 292 | 293 | 294 | ### 感觉还不错?请投出您的 [**Star**](https://github.com/Fliggy-Mobile/fdottedline) 吧 🥰 ! 295 | 296 | 297 | --- 298 | 299 | # 如何运行 Demo 工程? 300 | 301 | 1.**clone** 工程到本地 302 | 303 | 2.进入工程 `example` 目录,运行以下命令 304 | 305 | ``` 306 | flutter create . 307 | ``` 308 | 309 | 3.运行 `example` 中的 Demo 310 | -------------------------------------------------------------------------------- /example/.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 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/Flutter/flutter_export_environment.sh 65 | **/ios/ServiceDefinitions.json 66 | **/ios/Runner/GeneratedPluginRegistrant.* 67 | 68 | # Exceptions to above rules. 69 | !**/ios/**/default.mode1v3 70 | !**/ios/**/default.mode2v3 71 | !**/ios/**/default.pbxuser 72 | !**/ios/**/default.perspectivev3 73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 74 | 75 | web/ 76 | .flutter-plugins-dependencies 77 | README.md 78 | test/ 79 | macos/ 80 | android/ 81 | ios/ 82 | test/ 83 | .metadata 84 | pubspec.lock 85 | README.md 86 | -------------------------------------------------------------------------------- /example/assets/icon_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fliggy-Mobile/fdottedline/d546bc8b3a74d923070e6fd76ca58d21ed5799dd/example/assets/icon_logo.png -------------------------------------------------------------------------------- /example/lib/color.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'package:flutter/widgets.dart'; 3 | 4 | const Color mainBackgroundColor = Color(0xfff1f3f6); 5 | const Color mainTextTitleColor = Color(0xff366471); 6 | const Color mainTextNormalColor = Color(0xff3e6a77); 7 | const Color mainTextSubColor = Color(0xff6c909b); 8 | const Color mainShadowColor = Color(0x4d3754AA); 9 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:fbutton/fbutton.dart'; 4 | import 'package:fdottedline_example/color.dart'; 5 | import 'package:fdottedline_example/part.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:fdottedline/fdottedline.dart'; 8 | import 'package:fsuper/fsuper.dart'; 9 | 10 | void main() => runApp(MyApp()); 11 | 12 | class MyApp extends StatefulWidget { 13 | @override 14 | _MyAppState createState() => _MyAppState(); 15 | } 16 | 17 | class _MyAppState extends State with TickerProviderStateMixin { 18 | AnimationController animController8; 19 | Animation anim8; 20 | bool forward = true; 21 | 22 | @override 23 | void initState() { 24 | animController8 = AnimationController(vsync: this); 25 | animController8.duration = Duration(milliseconds: 1000); 26 | anim8 = Tween(begin: 0.0, end: 200.0).animate( 27 | CurvedAnimation(parent: animController8, curve: Curves.easeInOutQuint)); 28 | animController8.addStatusListener((status) { 29 | if (status == AnimationStatus.forward) { 30 | forward = !forward; 31 | } else if (status == AnimationStatus.reverse) { 32 | forward = !forward; 33 | } 34 | }); 35 | super.initState(); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return MaterialApp( 41 | color: mainBackgroundColor, 42 | home: Scaffold( 43 | backgroundColor: mainBackgroundColor, 44 | appBar: AppBar( 45 | backgroundColor: mainBackgroundColor, 46 | title: const Text( 47 | 'FDottedLine', 48 | style: TextStyle(color: mainTextTitleColor), 49 | ), 50 | centerTitle: true, 51 | ), 52 | body: SingleChildScrollView( 53 | physics: BouncingScrollPhysics(), 54 | child: Column( 55 | crossAxisAlignment: CrossAxisAlignment.center, 56 | mainAxisSize: MainAxisSize.min, 57 | children: [ 58 | buildTitle("Horizontal"), 59 | buildBigMargin(), 60 | 61 | /// demo1 62 | buildDemo1(), 63 | buildBigMargin(), 64 | buildTitle("Vertical"), 65 | buildBigMargin(), 66 | 67 | /// demo2 68 | buildDemo2(), 69 | 70 | buildBigMargin(), 71 | buildTitle("Shape"), 72 | buildBigMargin(), 73 | 74 | /// demo3 75 | buildDemo3(), 76 | 77 | buildBigMargin(), 78 | buildTitle("Corner"), 79 | buildBigMargin(), 80 | 81 | /// demo4 82 | buildDemo4(), 83 | 84 | buildBigMargin(), 85 | buildTitle("Child"), 86 | buildBigMargin(), 87 | 88 | /// demo5 89 | buildDemo5(), 90 | 91 | buildBigMargin(), 92 | 93 | /// demo6 94 | buildDemo6(), 95 | 96 | buildBigMargin(), 97 | buildTitle("More"), 98 | buildBigMargin(), 99 | 100 | /// demo7 101 | buildDemo7(), 102 | 103 | buildBigMargin(), 104 | buildBigMargin(), 105 | 106 | /// demo8 107 | buildDemo8(), 108 | 109 | buildBiggestMargin(), 110 | buildBiggestMargin(), 111 | buildBiggestMargin(), 112 | ], 113 | ), 114 | ), 115 | ), 116 | ); 117 | } 118 | 119 | Widget buildDemo1() { 120 | return FSuper( 121 | width: 200, 122 | height: 200, 123 | backgroundColor: mainBackgroundColor, 124 | child1: FDottedLine( 125 | color: mainTextSubColor, 126 | width: 160.0, 127 | strokeWidth: 2.0, 128 | dottedLength: 10.0, 129 | space: 2.0, 130 | ), 131 | child1Alignment: Alignment.center, 132 | shadowColor: mainShadowColor, 133 | shadowBlur: 5.0, 134 | shadowOffset: Offset(2.0, 2.0), 135 | corner: Corner.all(9.0), 136 | ); 137 | } 138 | 139 | Widget buildDemo2() { 140 | return FSuper( 141 | width: 200, 142 | height: 200, 143 | backgroundColor: mainBackgroundColor, 144 | child1: FDottedLine( 145 | color: mainTextSubColor, 146 | height: 160.0, 147 | strokeWidth: 2.0, 148 | dottedLength: 10.0, 149 | space: 2.0, 150 | ), 151 | child1Alignment: Alignment.center, 152 | shadowColor: mainShadowColor, 153 | shadowBlur: 5.0, 154 | shadowOffset: Offset(2.0, 2.0), 155 | corner: Corner.all(9.0), 156 | ); 157 | } 158 | 159 | Widget buildDemo3() { 160 | return FSuper( 161 | width: MediaQueryData.fromWindow(window).size.width - 40.0, 162 | height: 200, 163 | backgroundColor: mainBackgroundColor, 164 | child1: Row( 165 | mainAxisAlignment: MainAxisAlignment.spaceAround, 166 | mainAxisSize: MainAxisSize.max, 167 | children: [ 168 | FDottedLine( 169 | color: Colors.lightBlue[600], 170 | height: 100.0, 171 | width: 50, 172 | strokeWidth: 2.0, 173 | dottedLength: 10.0, 174 | space: 2.0, 175 | ), 176 | FDottedLine( 177 | color: Colors.red, 178 | height: 50.0, 179 | width: 100.0, 180 | strokeWidth: 2.0, 181 | dottedLength: 10.0, 182 | space: 2.0, 183 | ), 184 | FDottedLine( 185 | color: Colors.amber[600], 186 | height: 100.0, 187 | width: 100, 188 | strokeWidth: 2.0, 189 | dottedLength: 10.0, 190 | space: 2.0, 191 | ), 192 | ], 193 | ), 194 | child1Alignment: Alignment.center, 195 | shadowColor: mainShadowColor, 196 | shadowBlur: 5.0, 197 | shadowOffset: Offset(2.0, 2.0), 198 | corner: Corner.all(9.0), 199 | ); 200 | } 201 | 202 | Widget buildDemo4() { 203 | return FSuper( 204 | width: MediaQueryData.fromWindow(window).size.width - 40.0, 205 | height: 200, 206 | backgroundColor: mainBackgroundColor, 207 | child1: Row( 208 | mainAxisAlignment: MainAxisAlignment.spaceAround, 209 | mainAxisSize: MainAxisSize.max, 210 | children: [ 211 | FDottedLine( 212 | color: Colors.lightBlue[600], 213 | height: 70.0, 214 | width: 70.0, 215 | strokeWidth: 2.0, 216 | dottedLength: 10.0, 217 | space: 2.0, 218 | corner: FDottedLineCorner.all(50), 219 | ), 220 | FDottedLine( 221 | color: Colors.green[600], 222 | height: 70.0, 223 | width: 70.0, 224 | strokeWidth: 2.0, 225 | dottedLength: 10.0, 226 | space: 2.0, 227 | corner: FDottedLineCorner( 228 | leftTopCorner: 35.0, 229 | rightTopCorner: 35.0, 230 | ), 231 | ), 232 | FDottedLine( 233 | color: Colors.red[600], 234 | height: 70.0, 235 | width: 70.0, 236 | strokeWidth: 2.0, 237 | dottedLength: 10.0, 238 | space: 2.0, 239 | corner: FDottedLineCorner.all(12), 240 | ), 241 | ], 242 | ), 243 | child1Alignment: Alignment.center, 244 | shadowColor: mainShadowColor, 245 | shadowBlur: 5.0, 246 | shadowOffset: Offset(2.0, 2.0), 247 | corner: Corner.all(9.0), 248 | ); 249 | } 250 | 251 | Widget buildDemo5() { 252 | return FSuper( 253 | width: 200, 254 | height: 200, 255 | backgroundColor: mainBackgroundColor, 256 | child1: FDottedLine( 257 | color: mainTextSubColor, 258 | strokeWidth: 2.0, 259 | dottedLength: 8.0, 260 | space: 3.0, 261 | child: Container( 262 | color: Colors.blue[100], 263 | width: 130, 264 | height: 70, 265 | alignment: Alignment.center, 266 | child: Text( 267 | "0873", 268 | textAlign: TextAlign.center, 269 | style: TextStyle( 270 | color: Colors.white, 271 | fontSize: 26, 272 | fontWeight: FontWeight.bold, 273 | letterSpacing: 5.0, 274 | ), 275 | ), 276 | ), 277 | corner: FDottedLineCorner.all(6.0), 278 | ), 279 | child1Alignment: Alignment.center, 280 | shadowColor: mainShadowColor, 281 | shadowBlur: 5.0, 282 | shadowOffset: Offset(2.0, 2.0), 283 | corner: Corner.all(9.0), 284 | ); 285 | } 286 | 287 | Widget buildDemo6() { 288 | return FSuper( 289 | width: 200, 290 | height: 200, 291 | backgroundColor: mainBackgroundColor, 292 | child1: FDottedLine( 293 | color: mainTextSubColor, 294 | strokeWidth: 2.0, 295 | dottedLength: 8.0, 296 | space: 3.0, 297 | corner: FDottedLineCorner.all(75.0), 298 | child: Container( 299 | width: 130, 300 | height: 130, 301 | alignment: Alignment.center, 302 | child: FDottedLine( 303 | color: mainTextSubColor, 304 | strokeWidth: 2.0, 305 | dottedLength: 8.0, 306 | space: 3.0, 307 | corner: FDottedLineCorner.all(20.0), 308 | child: Container( 309 | width: 43.0, 310 | height: 43.0, 311 | color: Colors.grey[900], 312 | ), 313 | ), 314 | ), 315 | ), 316 | child1Alignment: Alignment.center, 317 | shadowColor: mainShadowColor, 318 | shadowBlur: 5.0, 319 | shadowOffset: Offset(2.0, 2.0), 320 | corner: Corner.all(9.0), 321 | ); 322 | } 323 | 324 | Widget buildDemo7() { 325 | return FSuper( 326 | width: 250, 327 | height: 350, 328 | backgroundColor: mainBackgroundColor, 329 | child1: FDottedLine( 330 | color: mainTextTitleColor, 331 | height: 160.0, 332 | strokeWidth: 2.0, 333 | dottedLength: 8.0, 334 | space: 3.0, 335 | child: Container( 336 | width: 150, 337 | height: 250, 338 | padding: 339 | EdgeInsets.only(left: 10.0, right: 10.0, top: 18.0, bottom: 12), 340 | child: Column( 341 | crossAxisAlignment: CrossAxisAlignment.center, 342 | children: [ 343 | Text( 344 | "BILL", 345 | style: TextStyle( 346 | color: Colors.blue, 347 | fontWeight: FontWeight.bold, 348 | fontSize: 23.0, 349 | ), 350 | ), 351 | const SizedBox(height: 20.0), 352 | buildBillItem("FSuper", "306"), 353 | buildBillItem("FButton", "58"), 354 | buildBillItem("FSwitch", "43"), 355 | buildBillItem("FRadio", "38"), 356 | buildBillItem("FFloat", "108"), 357 | buildBillItem("FRefresh", "233"), 358 | const SizedBox(height: 16.0), 359 | FDottedLine( 360 | color: mainTextTitleColor, 361 | width: double.infinity, 362 | dottedLength: 2.0, 363 | strokeWidth: 5.0, 364 | space: 2.0, 365 | ), 366 | const SizedBox(height: 10.0), 367 | buildBillItem("Total", "786"), 368 | const SizedBox(height: 25.0), 369 | FSuper( 370 | text: "Fliggy-Mobile", 371 | textColor: mainTextTitleColor, 372 | textSize: 10.0, 373 | padding: EdgeInsets.only(left: 16.0), 374 | child1: Image.asset( 375 | "assets/icon_logo.png", 376 | width: 15, 377 | height: 15, 378 | ), 379 | child1Alignment: Alignment.centerLeft, 380 | ), 381 | ], 382 | ), 383 | ), 384 | ), 385 | child1Alignment: Alignment.center, 386 | shadowColor: mainShadowColor, 387 | shadowBlur: 5.0, 388 | shadowOffset: Offset(2.0, 2.0), 389 | corner: Corner.all(9.0), 390 | ); 391 | } 392 | 393 | Widget buildBillItem(String title, String text) { 394 | return Row( 395 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 396 | children: [ 397 | Text( 398 | title, 399 | style: TextStyle( 400 | color: mainTextTitleColor, fontSize: 13.0, height: 1.18), 401 | ), 402 | Text( 403 | text, 404 | style: TextStyle( 405 | color: mainTextTitleColor, fontSize: 13.0, height: 1.18), 406 | ), 407 | ], 408 | ); 409 | } 410 | 411 | double w8 = 0.0; 412 | 413 | VoidCallback listener8; 414 | 415 | Widget buildDemo8() { 416 | return StatefulBuilder(builder: (context, setState) { 417 | if (listener8 == null) { 418 | animController8.addListener(listener8 = () { 419 | setState(() {}); 420 | }); 421 | } 422 | return Row( 423 | mainAxisAlignment: MainAxisAlignment.center, 424 | children: [ 425 | FSuper( 426 | width: 200, 427 | height: 60, 428 | backgroundColor: Color(0xff64B5F6), 429 | shadowBlur: 5.0, 430 | shadowColor: mainShadowColor, 431 | shadowOffset: Offset(3.0, 3.0), 432 | corner: Corner.all(6.0), 433 | child1: FDottedLine( 434 | width: anim8.value, 435 | strokeWidth: 10.0, 436 | color: Colors.lightBlue[50], 437 | dottedLength: 3.0, 438 | ), 439 | child1Alignment: Alignment.centerLeft, 440 | child1Margin: EdgeInsets.only(top: 5.5), 441 | ), 442 | const SizedBox(width: 25.0), 443 | FButton( 444 | width: 50, 445 | height: 50, 446 | padding: EdgeInsets.zero, 447 | corner: FButtonCorner.all(25), 448 | color: Colors.red, 449 | text: "Tread", 450 | textColor: Colors.white, 451 | fontSize: 15, 452 | effect: true, 453 | onPressed: () { 454 | if (forward) { 455 | animController8.forward(); 456 | } else { 457 | animController8.reverse(); 458 | } 459 | }, 460 | ) 461 | ], 462 | ); 463 | }); 464 | } 465 | } 466 | -------------------------------------------------------------------------------- /example/lib/part.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'color.dart'; 4 | 5 | Container buildTitle(String title) { 6 | return Container( 7 | alignment: Alignment.centerLeft, 8 | padding: EdgeInsets.all(9), 9 | color: Color(0xffe0e0e0).withOpacity(0.38), 10 | child: Text( 11 | title, 12 | style: TextStyle(color: mainTextSubColor.withOpacity(0.7)), 13 | ), 14 | ); 15 | } 16 | 17 | SizedBox buildBiggestMargin() { 18 | return const SizedBox( 19 | height: 66, 20 | ); 21 | } 22 | 23 | SizedBox buildBigMargin() { 24 | return const SizedBox( 25 | height: 36, 26 | ); 27 | } 28 | 29 | SizedBox buildMiddleMargin() { 30 | return const SizedBox( 31 | height: 26, 32 | ); 33 | } 34 | 35 | SizedBox buildSmallMargin() { 36 | return const SizedBox( 37 | height: 18, 38 | ); 39 | } 40 | 41 | Padding buildDesc(String desc) { 42 | return Padding( 43 | padding: const EdgeInsets.all(8), 44 | child: Text( 45 | desc, 46 | textAlign: TextAlign.center, 47 | style: TextStyle( 48 | color: Colors.grey, 49 | fontSize: 12, 50 | ), 51 | )); 52 | } 53 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fdottedline_example 2 | description: Demonstrates how to use the fdottedline plugin. 3 | publish_to: 'none' 4 | 5 | environment: 6 | sdk: ">=2.1.0 <3.0.0" 7 | 8 | dependencies: 9 | flutter: 10 | sdk: flutter 11 | 12 | # The following adds the Cupertino Icons font to your application. 13 | # Use with the CupertinoIcons class for iOS style icons. 14 | cupertino_icons: ^0.1.2 15 | fsuper: ^0.1.5 16 | fradio: ^1.0.1 17 | ffloat: ^1.0.0 18 | fswitch: ^1.1.2 19 | fbutton: ^1.0.4 20 | frefresh: ^1.1.0 21 | 22 | dev_dependencies: 23 | flutter_test: 24 | sdk: flutter 25 | 26 | fdottedline: 27 | path: ../ 28 | 29 | # For information on the generic Dart part of this file, see the 30 | # following page: https://dart.dev/tools/pub/pubspec 31 | 32 | # The following section is specific to Flutter. 33 | flutter: 34 | 35 | # The following line ensures that the Material Icons font is 36 | # included with your application, so that you can use the icons in 37 | # the material Icons class. 38 | uses-material-design: true 39 | 40 | # To add assets to your application, add an assets section, like this: 41 | assets: 42 | - assets/ 43 | # - images/a_dot_burr.jpeg 44 | # - images/a_dot_ham.jpeg 45 | 46 | # An image asset can refer to one or more resolution-specific "variants", see 47 | # https://flutter.dev/assets-and-images/#resolution-aware. 48 | 49 | # For details regarding adding assets from package dependencies, see 50 | # https://flutter.dev/assets-and-images/#from-packages 51 | 52 | # To add custom fonts to your application, add a fonts section here, 53 | # in this "flutter" section. Each entry in this list should have a 54 | # "family" key with the font family name, and a "fonts" key with a 55 | # list giving the asset and other descriptors for the font. For 56 | # example: 57 | # fonts: 58 | # - family: Schyler 59 | # fonts: 60 | # - asset: fonts/Schyler-Regular.ttf 61 | # - asset: fonts/Schyler-Italic.ttf 62 | # style: italic 63 | # - family: Trajan Pro 64 | # fonts: 65 | # - asset: fonts/TrajanPro.ttf 66 | # - asset: fonts/TrajanPro_Bold.ttf 67 | # weight: 700 68 | # 69 | # For details regarding fonts from package dependencies, 70 | # see https://flutter.dev/custom-fonts/#from-packages 71 | -------------------------------------------------------------------------------- /lib/fdottedline.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | bool _isEmpty(double d) { 6 | return d == null || d == 0.0; 7 | } 8 | 9 | /// 圆角。 10 | /// 11 | /// corner 12 | class FDottedLineCorner { 13 | final double leftTopCorner; 14 | final double rightTopCorner; 15 | final double rightBottomCorner; 16 | final double leftBottomCorner; 17 | 18 | /// 指定每一个圆角的大小 19 | /// 20 | /// Specify the size of each rounded corner 21 | const FDottedLineCorner({ 22 | this.leftTopCorner = 0, 23 | this.rightTopCorner = 0, 24 | this.rightBottomCorner = 0, 25 | this.leftBottomCorner = 0, 26 | }); 27 | 28 | /// 设置所有圆角为一个大小 29 | /// 30 | /// Set all rounded corners to one size 31 | FDottedLineCorner.all(double radius) 32 | : leftTopCorner = radius, 33 | rightTopCorner = radius, 34 | rightBottomCorner = radius, 35 | leftBottomCorner = radius; 36 | } 37 | 38 | class FDottedLine extends StatefulWidget { 39 | /// 虚线颜色 40 | /// 41 | /// Dotted line color 42 | final Color color; 43 | 44 | /// 高。如果只有 [height],而没有 [width],将获得一个垂直方向的虚线 45 | /// 如果同时有 [width] 和 [height],将获得一个虚线边框。 46 | /// 47 | /// height. If there is only [height] and no [width], you will get a dotted line in the vertical direction 48 | /// If there are both [width] and [height], you will get a dotted border. 49 | final double height; 50 | 51 | /// 宽。如果只有 [width],而没有 [height],将获得一个水平方向的虚线 52 | /// 如果同时有 [width] 和 [height],将获得一个虚线边框。 53 | /// 54 | /// width. If there is only [width] and no [height], you will get a dotted line in the horizontal direction 55 | /// If there are both [width] and [height], you will get a dotted border. 56 | final double width; 57 | 58 | /// 虚线的厚度 59 | /// 60 | /// The thickness of the dotted line 61 | final double strokeWidth; 62 | 63 | /// 虚线中每一小段的长 64 | /// 65 | /// The length of each small segment in the dotted line 66 | final double dottedLength; 67 | 68 | /// 虚线中每段间的距离 69 | /// 70 | /// The distance between each segment in the dotted line 71 | final double space; 72 | 73 | /// 虚线边框的边角。详见 [FDottedLineCorner] 74 | /// 75 | /// The corners of the dotted border. See [FDottedLineCorner] for details 76 | final FDottedLineCorner corner; 77 | 78 | /// 如果设置了 [child],[FDottedLine] 将会作为 [child] 的虚线边框。 79 | /// 此时,[width] 和 [height] 将不再有效。 80 | /// 81 | /// If [child] is set, [FDottedLine] will serve as the dotted border of [child]. 82 | /// At this time, [width] and [height] will no longer be valid. 83 | final Widget child; 84 | 85 | /// [FDottedLine] 为开发者提供了创建虚线的能力。同时支持为一个 [Widget] 创建虚线边框。支持控制虚线的粗细,间距,以及虚线边框的边角。 86 | /// 87 | /// [FDottedLine] provides developers with the ability to create dashed lines. It also supports creating a dashed border for a [Widget]. Support for controlling the thickness, spacing, and corners of the dotted border. 88 | FDottedLine({ 89 | Key key, 90 | this.color = Colors.black, 91 | this.height, 92 | this.width, 93 | this.dottedLength = 5.0, 94 | this.space = 3.0, 95 | this.strokeWidth = 1.0, 96 | this.corner, 97 | this.child, 98 | }) : super(key: key) { 99 | assert(width != null || height != null || child != null); 100 | } 101 | 102 | @override 103 | _FDottedLineState createState() => _FDottedLineState(); 104 | } 105 | 106 | class _FDottedLineState extends State { 107 | double childWidth; 108 | double childHeight; 109 | GlobalKey childKey = GlobalKey(); 110 | 111 | @override 112 | Widget build(BuildContext context) { 113 | if (_isEmpty(widget.width) && _isEmpty(widget.height) && widget.child == null) return Container(); 114 | if (widget.child != null) { 115 | tryToGetChildSize(); 116 | List children = []; 117 | children.add(Container( 118 | clipBehavior: widget.corner == null ? Clip.none : Clip.antiAlias, 119 | decoration: BoxDecoration( 120 | borderRadius: BorderRadius.only( 121 | topLeft: Radius.circular( 122 | widget.corner != null ? widget.corner.leftTopCorner : 0.0), 123 | topRight: Radius.circular( 124 | widget.corner != null ? widget.corner.rightTopCorner : 0.0), 125 | bottomLeft: Radius.circular( 126 | widget.corner != null ? widget.corner.leftBottomCorner : 0.0), 127 | bottomRight: Radius.circular( 128 | widget.corner != null ? widget.corner.rightBottomCorner : 0.0), 129 | ), 130 | ), 131 | key: childKey, 132 | child: widget.child, 133 | )); 134 | if (childWidth != null && childHeight != null) { 135 | children.add(dashPath(width: childWidth, height: childHeight)); 136 | } 137 | return Stack( 138 | children: children, 139 | ); 140 | } else { 141 | return dashPath(width: widget.width, height: widget.height); 142 | } 143 | } 144 | 145 | void tryToGetChildSize() { 146 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) { 147 | try { 148 | RenderBox box = childKey.currentContext.findRenderObject(); 149 | double tempWidth = box.size.width; 150 | double tempHeight = box.size.height; 151 | bool needUpdate = tempWidth != childWidth || tempHeight != childHeight; 152 | if (needUpdate) { 153 | setState(() { 154 | childWidth = tempWidth; 155 | childHeight = tempHeight; 156 | }); 157 | } 158 | } catch (e, stack) {} 159 | }); 160 | } 161 | 162 | CustomPaint dashPath({double width, double height}) { 163 | return CustomPaint( 164 | size: Size(_isEmpty(width) ? widget.strokeWidth : width, 165 | _isEmpty(height) ? widget.strokeWidth : height), 166 | foregroundPainter: _DottedLinePainter() 167 | ..color = widget.color 168 | ..dottedLength = widget.dottedLength 169 | ..space = widget.space 170 | ..strokeWidth = widget.strokeWidth 171 | ..corner = widget.corner 172 | ..isShape = !_isEmpty(height) && !_isEmpty(width), 173 | ); 174 | } 175 | } 176 | 177 | class _DottedLinePainter extends CustomPainter { 178 | Color color; 179 | double dottedLength; 180 | double space; 181 | double strokeWidth; 182 | bool isShape; 183 | FDottedLineCorner corner; 184 | Radius topLeft = Radius.zero; 185 | Radius topRight = Radius.zero; 186 | Radius bottomRight = Radius.zero; 187 | Radius bottomLeft = Radius.zero; 188 | 189 | @override 190 | void paint(Canvas canvas, Size size) { 191 | var isHorizontal = size.width > size.height; 192 | final Paint paint = Paint() 193 | ..isAntiAlias = true 194 | ..filterQuality = FilterQuality.high 195 | ..color = color 196 | ..style = PaintingStyle.stroke 197 | ..strokeWidth = strokeWidth; 198 | 199 | /// 线段 200 | /// 201 | /// line 202 | if (!isShape) { 203 | double length = isHorizontal ? size.width : size.height; 204 | double count = (length) / (dottedLength + space); 205 | if (count < 2.0) return; 206 | var startOffset = Offset(0, 0); 207 | for (int i = 0; i < count.toInt(); i++) { 208 | canvas.drawLine( 209 | startOffset, 210 | startOffset.translate((isHorizontal ? dottedLength : 0), 211 | (isHorizontal ? 0 : dottedLength)), 212 | paint); 213 | startOffset = startOffset.translate( 214 | (isHorizontal ? (dottedLength + space) : 0), 215 | (isHorizontal ? 0 : (dottedLength + space))); 216 | } 217 | } 218 | 219 | /// 形状 220 | /// 221 | /// shape 222 | else { 223 | Path path = Path(); 224 | path.addRRect(RRect.fromLTRBAndCorners( 225 | 0, 226 | 0, 227 | size.width, 228 | size.height, 229 | topLeft: Radius.circular(corner != null ? corner.leftTopCorner : 0.0), 230 | topRight: Radius.circular(corner != null ? corner.rightTopCorner : 0.0), 231 | bottomLeft: 232 | Radius.circular(corner != null ? corner.leftBottomCorner : 0.0), 233 | bottomRight: 234 | Radius.circular(corner != null ? corner.rightBottomCorner : 0.0), 235 | )); 236 | 237 | Path draw = buildDashPath(path, dottedLength, space); 238 | canvas.drawPath(draw, paint); 239 | } 240 | } 241 | 242 | Path buildDashPath(Path path, double dottedLength, double space) { 243 | final Path r = Path(); 244 | for (PathMetric metric in path.computeMetrics()) { 245 | double start = 0.0; 246 | while (start < metric.length) { 247 | double end = start + dottedLength; 248 | r.addPath(metric.extractPath(start, end), Offset.zero); 249 | start = end + space; 250 | } 251 | } 252 | return r; 253 | } 254 | 255 | @override 256 | bool shouldRepaint(_DottedLinePainter oldDelegate) { 257 | return true; 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: fdottedline 2 | description: Help developers realize the dotted line in the simplest way. 3 | version: 1.0.1 4 | author: CoorChice 5 | homepage: https://github.com/Fliggy-Mobile/fdottedline 6 | 7 | environment: 8 | sdk: ">=2.1.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | # For information on the generic Dart part of this file, see the 19 | # following page: https://dart.dev/tools/pub/pubspec 20 | 21 | # The following section is specific to Flutter. 22 | flutter: 23 | # This section identifies this Flutter project as a plugin project. 24 | # The androidPackage and pluginClass identifiers should not ordinarily 25 | # be modified. They are used by the tooling to maintain consistency when 26 | # adding or updating assets for this project. 27 | # plugin: 28 | # androidPackage: com.taobao.trip.fdottedline 29 | # pluginClass: FdottedlinePlugin 30 | 31 | # To add assets to your plugin package, add an assets section, like this: 32 | # assets: 33 | # - images/a_dot_burr.jpeg 34 | # - images/a_dot_ham.jpeg 35 | # 36 | # For details regarding assets in packages, see 37 | # https://flutter.dev/assets-and-images/#from-packages 38 | # 39 | # An image asset can refer to one or more resolution-specific "variants", see 40 | # https://flutter.dev/assets-and-images/#resolution-aware. 41 | 42 | # To add custom fonts to your plugin package, add a fonts section here, 43 | # in this "flutter" section. Each entry in this list should have a 44 | # "family" key with the font family name, and a "fonts" key with a 45 | # list giving the asset and other descriptors for the font. For 46 | # example: 47 | # fonts: 48 | # - family: Schyler 49 | # fonts: 50 | # - asset: fonts/Schyler-Regular.ttf 51 | # - asset: fonts/Schyler-Italic.ttf 52 | # style: italic 53 | # - family: Trajan Pro 54 | # fonts: 55 | # - asset: fonts/TrajanPro.ttf 56 | # - asset: fonts/TrajanPro_Bold.ttf 57 | # weight: 700 58 | # 59 | # For details regarding fonts in packages, see 60 | # https://flutter.dev/custom-fonts/#from-packages 61 | -------------------------------------------------------------------------------- /test/fdottedline_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:fdottedline/fdottedline.dart'; 4 | 5 | void main() { 6 | // const MethodChannel channel = MethodChannel('fdottedline'); 7 | // 8 | // TestWidgetsFlutterBinding.ensureInitialized(); 9 | // 10 | // setUp(() { 11 | // channel.setMockMethodCallHandler((MethodCall methodCall) async { 12 | // return '42'; 13 | // }); 14 | // }); 15 | // 16 | // tearDown(() { 17 | // channel.setMockMethodCallHandler(null); 18 | // }); 19 | // 20 | // test('getPlatformVersion', () async { 21 | // expect(await Fdottedline.platformVersion, '42'); 22 | // }); 23 | } 24 | --------------------------------------------------------------------------------