diff --git a/example/lib/main.dart b/example/lib/main.dart index cc029e6a..7b616839 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -14,7 +14,6 @@ class MyApp extends StatelessWidget { ); } -// class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); diff --git a/example/pubspec.lock b/example/pubspec.lock index 53123d5c..8b137891 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -1,243 +1 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.3" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.14.13" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "0.18.1" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - getwidget: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "1.1.3" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.8" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.8" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.1+1" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.4" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.4" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.5" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.5" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.17" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - url: "https://pub.dartlang.org" - source: hosted - version: "5.4.1" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.1+2" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.5" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.0" -sdks: - dart: ">=2.9.0-14.0.dev <3.0.0" - flutter: ">=1.18.0-6.0.pre <2.0.0" + diff --git a/lib/components/border/gf_border.dart b/lib/components/border/gf_border.dart new file mode 100644 index 00000000..3f74b802 --- /dev/null +++ b/lib/components/border/gf_border.dart @@ -0,0 +1,76 @@ +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:getwidget/components/border/gf_dashed_border.dart'; +import 'package:getwidget/types/gf_border_type.dart'; + +class GFBorder extends StatelessWidget { + GFBorder({ + @required this.child, + this.color = Colors.black, + this.strokeWidth = 1, + this.type = GFBorderType.Rect, + this.dashedLine = const [3, 1], + this.padding = const EdgeInsets.all(10), + this.radius = const Radius.circular(0), + this.customPath, + }) : assert(child != null), + assert(_isValiddashedLine(dashedLine), 'Invalid dash pattern'); + + /// child of type [Widget] which can be any component or text , etc + final Widget child; + + /// padding of time [EdgeInsets] where in padding is given to the border types + final EdgeInsets padding; + + /// storkeWidth of type [double] which is used to define the thickness of the border + final double strokeWidth; + + /// color of type [Color] or GFColor which is used to change the color of the border type + final Color color; + + /// dashedLine of type [List] which is used for the linear and simple dashed line of border + final List dashedLine; + + /// type of [GFBorderType] which is used to define the different types of borders ie, circle, Rect, RRect and oval + final GFBorderType type; + + /// radius of type [Radius] used to give a curved border only when the border type is RRect, in other cases radius will not work + final Radius radius; + + /// customPath of type [PathBuilder] used for drawing the paths + final PathBuilder customPath; + + @override + Widget build(BuildContext context) => Stack( + children: [ + Positioned.fill( + child: CustomPaint( + painter: DashedType( + strokeWidth: strokeWidth, + radius: radius, + color: color, + type: type, + dashedLine: dashedLine, + customPath: customPath, + ), + ), + ), + Container(padding: padding, child: child), + ], + ); +} + +/// the value of dashedLine cannot be 0 or null, it should have some definite and proper value +bool _isValiddashedLine(List dash) { + final Set _dashSet = dash.toSet(); + if (_dashSet == null) { + return false; + } + if (_dashSet.length == 1 && _dashSet.elementAt(0) == 0.0) { + return false; + } + if (_dashSet.isEmpty) { + return false; + } + return true; +} diff --git a/lib/components/border/gf_dashed_border.dart b/lib/components/border/gf_dashed_border.dart new file mode 100644 index 00000000..fc56c3b8 --- /dev/null +++ b/lib/components/border/gf_dashed_border.dart @@ -0,0 +1,199 @@ +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:getwidget/types/gf_border_type.dart'; + +typedef PathBuilder = Path Function(Size); + +class DashedType extends CustomPainter { + DashedType({ + this.strokeWidth = 2, + this.dashedLine = const [3, 1], + this.color = Colors.black, + this.type = GFBorderType.Rect, + this.radius = const Radius.circular(0), + this.customPath, + }) : assert(dashedLine.isNotEmpty, 'dash line cannot be empty'); + + /// storkeWidth of type [double] which is used to define the thickness of the border + final double strokeWidth; + + /// dashedLine of type [List] which is used for the linear and simple dashed line of border + final List dashedLine; + + /// color of type [Color] or GFColor which is used to change the color of the border type + final Color color; + + /// type of [GFBorderType] which is used to define the different types of borders ie, circle, Rect, RRect and oval + final GFBorderType type; + + /// radius of type [Radius] used to give a curved border only when the border type is RRect, in other cases radius will not work + final Radius radius; + + /// customPath of type [PathBuilder] used for the drawing the paths + final PathBuilder customPath; + + @override + void paint(Canvas canvas, Size size) { + final Paint paint = Paint() + ..strokeWidth = strokeWidth + ..color = color + ..style = PaintingStyle.stroke; + + Path _path; + if (customPath != null) { + _path = dashPath( + customPath(size), + dashedarray: CircularIntervalList(dashedLine), + ); + } else { + _path = _getPath(size); + } + + canvas.drawPath(_path, paint); + } + + /// Returns a [Path] based on the the borderType parameter + Path _getPath(Size size) { + Path path; + switch (type) { + case GFBorderType.Circle: + path = _getCirclePath(size); + break; + case GFBorderType.RRect: + path = _getRRectPath(size, radius); + break; + case GFBorderType.Rect: + path = _getRectPath(size); + break; + case GFBorderType.Oval: + path = _getOvalPath(size); + break; + } + + return dashPath(path, dashedarray: CircularIntervalList(dashedLine)); + } + + /// gives a circular path of borderType + Path _getCirclePath(Size size) { + final double width = size.width; + final double height = size.height; + final double sizes = size.shortestSide; + + return Path() + ..addRRect( + RRect.fromRectAndRadius( + Rect.fromLTWH( + width > sizes ? (width - sizes) / 2 : 0, + height > sizes ? (height - sizes / 2) : 0, + sizes, + sizes, + ), + Radius.circular(sizes / 2), + ), + ); + } + + /// gives a Rounded Rectangular Path with [radius] of [size] for borderType + + Path _getRRectPath(Size size, Radius radius) => Path() + ..addRRect( + RRect.fromRectAndRadius( + Rect.fromLTWH( + 0, + 0, + size.width, + size.height, + ), + radius, + ), + ); + + /// gives a Rectangular Path with [size] for borderType + Path _getRectPath(Size size) => Path() + ..addRect( + Rect.fromLTWH( + 0, + 0, + size.width, + size.height, + ), + ); + + /// gives an oval path of [size] for borderType + Path _getOvalPath(Size size) => Path() + ..addOval( + Rect.fromLTWH( + 0, + 0, + size.width, + size.height, + ), + ); + + @override + bool shouldRepaint(DashedType oldDelegate) => + oldDelegate.strokeWidth != strokeWidth || + oldDelegate.color != color || + oldDelegate.dashedLine != dashedLine || + oldDelegate.type != type; +} + +class CircularIntervalList { + CircularIntervalList(this.values); + + final List values; + int index = 0; + + T get next { + if (index >= values.length) { + index = 0; + } + return values[index++]; + } +} + +Path dashPath(Path source, + {@required CircularIntervalList dashedarray, + DashOffset dashOffset = const DashOffset.absolute(0)}) { + assert(dashedarray != null); + if (source == null) { + return null; + } + + final Path dest = Path(); + for (final PathMetric metric in source.computeMetrics()) { + double distance = dashOffset._calculate(metric.length); + bool draw = true; + while (distance < metric.length) { + final double len = dashedarray.next; + if (draw) { + dest.addPath(metric.extractPath(distance, distance + len), Offset.zero); + } + distance += len; + draw = !draw; + } + } + + return dest; +} + +/// Specifies the starting position of a dashed array or line on a path, either as a percentage or absolute +enum _DashOffsetType { Absolute, Percentage } + +class DashOffset { + ///gives offset of the dashed path that will be measured as a percentage which ranges from 0.0 to 1.0 + DashOffset.percentage(double percentage) + : _value = percentage.clamp(0.0, 1.0) ?? 0.0, + _dashOffsetType = _DashOffsetType.Percentage; + + ///gives offset of the dashed path that will be measured as a absolute value + const DashOffset.absolute(double start) + : _value = start ?? 0.0, + _dashOffsetType = _DashOffsetType.Absolute; + + final double _value; + final _DashOffsetType _dashOffsetType; + + double _calculate(double length) => + _dashOffsetType == _DashOffsetType.Absolute ? _value : length * _value; +} diff --git a/lib/getwidget.dart b/lib/getwidget.dart index c44d2755..f5a26318 100644 --- a/lib/getwidget.dart +++ b/lib/getwidget.dart @@ -34,6 +34,7 @@ export 'package:getwidget/components/shimmer/gf_shimmer.dart'; export 'package:getwidget/components/loader/gf_loader.dart'; export 'package:getwidget/components/progress_bar/gf_progress_bar.dart'; export 'package:getwidget/components/checkbox/gf_checkbox.dart'; +export 'package:getwidget/components/border/gf_border.dart'; export 'package:getwidget/components/checkbox_list_tile/gf_checkbox_list_tile.dart'; export 'package:getwidget/components/radio/gf_radio.dart'; export 'package:getwidget/components/radio_list_tile/gf_radio_list_tile.dart'; @@ -48,6 +49,7 @@ export 'shape/gf_button_shape.dart'; export 'shape/gf_icon_button_shape.dart'; export 'size/gf_size.dart'; export 'types/gf_alert_type.dart'; +export 'types/gf_border_type.dart'; export 'types/gf_button_type.dart'; export 'types/gf_checkbox_type.dart'; export 'types/gf_loader_type.dart'; diff --git a/lib/types/gf_border_type.dart b/lib/types/gf_border_type.dart new file mode 100644 index 00000000..bea0b2a9 --- /dev/null +++ b/lib/types/gf_border_type.dart @@ -0,0 +1 @@ +enum GFBorderType { Circle, RRect, Rect, Oval } diff --git a/pubspec.lock b/pubspec.lock index add20c53..8b137891 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,146 +1 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.3" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.14.13" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.8" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.8" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.9.5" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.5" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.17" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.8" -sdks: - dart: ">=2.9.0-14.0.dev <3.0.0" \ No newline at end of file +