├── screenshots └── logo.png ├── test └── dotted_line_flutter_test.dart ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── dart.yml ├── .metadata ├── lib ├── dotted_line_flutter.dart └── shape │ ├── dotted_text.dart │ ├── dotted_star.dart │ ├── dotted_cube.dart │ ├── dotted_line.dart │ ├── dotted_widget.dart │ └── dotted_shapes.dart ├── CONTRIBUTING.md ├── .gitignore ├── SECURITY.md ├── CHANGELOG.md ├── PULL_REQUEST_TEMPLATE.md ├── pubspec.yaml ├── LICENSE ├── CODE_OF_CONDUCT.md ├── analysis_options.yaml ├── example └── main.dart └── README.md /screenshots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iamapuneet/dotted_line_flutter/HEAD/screenshots/logo.png -------------------------------------------------------------------------------- /test/dotted_line_flutter_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | test('adds one to input values', () {}); 5 | } 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2. Every time someone opens a PR, this template will be automatically applied. 2 | 3 | --- 4 | 5 | This ensures all pull requests are **well-structured and easy to review**. 🚀 Let me know if you need any modifications! 😊 6 | -------------------------------------------------------------------------------- /.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: f468f3366c26a5092eb964a230ce7892fda8f2f8 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Dart (Flutter) Dependencies 4 | - package-ecosystem: "pub" 5 | directory: "/" # Location of pubspec.yaml 6 | schedule: 7 | interval: "monthly" 8 | 9 | # GitHub Actions Dependencies (Optional) 10 | - package-ecosystem: "github-actions" 11 | directory: "/" 12 | schedule: 13 | interval: "monthly" 14 | -------------------------------------------------------------------------------- /lib/dotted_line_flutter.dart: -------------------------------------------------------------------------------- 1 | library dotted_line_flutter; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'dart:ui'; 6 | import 'dart:ui' as ui; 7 | 8 | import 'dart:math'; 9 | part 'shape/dotted_cube.dart'; 10 | part 'shape/dotted_line.dart'; 11 | part 'shape/dotted_shapes.dart'; 12 | 13 | part 'shape/dotted_star.dart'; 14 | part 'shape/dotted_text.dart'; 15 | part 'shape/dotted_widget.dart'; 16 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for considering contributing to **dotted_line_flutter**! 🚀 4 | We appreciate your help in improving this project. Please follow these guidelines before contributing. 5 | 6 | --- 7 | 8 | ## 📌 How to Contribute? 9 | 10 | 1. **Fork the repository** 11 | Click on the "Fork" button at the top-right of this repository to create a copy under your GitHub account. 12 | 13 | 2. **Clone your fork** 14 | Run the following command to clone the forked repository to your local system: 15 | ```sh 16 | git clone https://github.com/iamapuneet/dotted_line_flutter.git 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.0.1 4 | - Initial release of DashedLine. 5 | 6 | ## 0.1.2 7 | - Added README. 8 | - Added custom gap color, line thickness, dash gap, and dash width. 9 | 10 | ## 0.1.3 11 | - Minor changes and improvements. 12 | 13 | ## 0.1.4 14 | - Fixed plugin configuration mismatch. 15 | - Corrected class names and package name. 16 | 17 | ## 2.1.8 18 | ### 🎉 New Features & Improvements: 19 | - ✅ **Dotted and Dashed Lines** 20 | - ✅ **Gradient Color Support** 21 | - ✅ **Customizable Dash Width & Gap** 22 | - ✅ **Horizontal & Vertical Orientation** 23 | - ✅ **Shadow Effect for Depth** 24 | - ✅ **More Shapes (Star, Circle, etc.)** 25 | - ✅ **Star Shape** 26 | - ✅ **Circle Dotted Line** 27 | - ✅ **Custom Dash Shapes** 28 | - ✅ **Patterned Dashes (Short-Long)** 29 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 📌 Pull Request Template 2 | 3 | ### 🔥 What does this PR do? 4 | - [ ] Bug Fix 🐛 5 | - [ ] New Feature ✨ 6 | - [ ] Documentation Update 📖 7 | - [ ] Code Refactor 🔄 8 | 9 | ### 📌 Description 10 | 11 | 12 | ### ✅ Checklist 13 | - [ ] My code follows the project’s style guidelines. 14 | - [ ] I have tested my changes locally. 15 | - [ ] I have updated documentation if required. 16 | 17 | ### 📢 Related Issues 18 | 19 | Fixes #Issue_Number 20 | 21 | ### 🚀 Screenshots (if applicable) 22 | 23 | 24 | ### 🛠 Testing Instructions 25 | 26 | 27 | --- 28 | 29 | ### ⚡ How to Use? 30 | 1. Save this file inside the `.github/` directory in your repository: 31 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dotted_line_flutter 2 | description: "This package allows you to draw dotted lines with Flutter. You can draw a beautiful dotted line." 3 | version: 2.1.8 4 | repository: https://github.com/iamapuneet/dotted_line_flutter.git 5 | issue_tracker: https://github.com/iamapuneet/dotted_line_flutter/issues 6 | homepage: https://github.com/iamapuneet/dotted_line_flutter?tab=readme-ov-file#dotted_line_flutter 7 | documentation: https://pub.dev/documentation/dotted_line_flutter/latest 8 | topics: [dotted-line, dotted, line-flutter, dotted-line-flutter] 9 | #funding: [https://github.com/sponsors/realpuneetsharam] 10 | 11 | environment: 12 | sdk: ">=3.5.3 <4.0.0" 13 | flutter: ">=1.17.0" 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | 19 | dev_dependencies: 20 | flutter_test: 21 | sdk: flutter 22 | 23 | screenshots: 24 | - description: The dotted lines Flutter package logo. 25 | path: screenshots/logo.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2025 Puneet Sharma 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | We as members, contributors, and leaders pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity, level of experience, nationality, personal appearance, race, religion, or sexual identity. 5 | 6 | ## Our Standards 7 | Examples of behavior that contribute to a positive environment include: 8 | - Being respectful and welcoming. 9 | - Giving and gracefully accepting constructive feedback. 10 | - Showing empathy towards others. 11 | 12 | Examples of unacceptable behavior include: 13 | - Harassment or offensive comments. 14 | - Personal attacks or political/religious discussions unrelated to the project. 15 | - Trolling or deliberate disruption. 16 | 17 | ## Enforcement 18 | Project maintainers have the right to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that do not align with this Code of Conduct. 19 | 20 | Instances of abusive behavior may be reported by contacting **[puneetsharma5525@gmail.com]**. 21 | 22 | By participating, you agree to abide by this Code of Conduct. 23 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | #include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at https://dart.dev/lints. 17 | # 18 | # Instead of disabling a lint rule for the entire project in the 19 | # section below, it can also be suppressed for a single line of code 20 | # or a specific dart file by using the `// ignore: name_of_lint` and 21 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 22 | # producing the lint. 23 | # rules: 24 | # - package_api_docs 25 | # - public_member_api_docs -------------------------------------------------------------------------------- /.github/workflows/dart.yml: -------------------------------------------------------------------------------- 1 | name: "Dart & Flutter Dotted Line Flutter Plugin" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | workflow_dispatch: 11 | 12 | permissions: 13 | contents: write 14 | 15 | jobs: 16 | build: 17 | name: Build & Release 18 | runs-on: windows-latest 19 | 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | 24 | - name: Create dist directory 25 | run: mkdir dist 26 | 27 | - name: Create tar.gz archive 28 | run: | 29 | tar --exclude=dist -czvf dist/dotted_line_flutter.tar.gz -C "${{ github.workspace }}" . 30 | 31 | - name: Create GitHub Release 32 | id: create_release 33 | uses: actions/create-release@v1 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | with: 37 | tag_name: v0.0.${{ github.run_number }} 38 | release_name: Release v0.0.${{ github.run_number }} 39 | draft: false 40 | makeLatest: true 41 | body: | 42 | 🎉 **Dotted Line Flutter - Release v0.0.${{ github.run_number }}** 🎉 43 | 44 | 🔥 **What's New**: 45 | ✅ **Dotted and Dashed Lines** 46 | ✅ **Gradient Color Support** 47 | ✅ **Customizable Dash Width & Gap** 48 | ✅ **Horizontal & Vertical Orientation** 49 | ✅ **Shadow Effect for Depth** 50 | ✅ **More Shapes (Star, Circle, etc.)** 51 | ✅ **Star Shape** 52 | ✅ **Circle Dotted Line** 53 | ✅ **Custom Dash Shapes** 54 | ✅ **Patterned Dashes (Short-Long)** 55 | 56 | 📢 **Developed by:** Puneet Sharma 57 | 🆔 **GitHub Id:** [@iamapuneet](https://github.com/iamapuneet) 58 | 💼 **Project:** Dotted Line Flutter 59 | 60 | 👉 **Download the latest release below!** 61 | 62 | - name: Upload tar.gz to Release 63 | uses: actions/upload-release-asset@v1 64 | env: 65 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 66 | with: 67 | upload_url: ${{ steps.create_release.outputs.upload_url }} 68 | asset_path: dist/dotted_line_flutter.tar.gz 69 | asset_name: dotted_line_flutter.tar.gz 70 | asset_content_type: application/gzip 71 | -------------------------------------------------------------------------------- /lib/shape/dotted_text.dart: -------------------------------------------------------------------------------- 1 | part of '../dotted_line_flutter.dart'; 2 | 3 | /// A custom widget that renders text using dotted patterns instead of solid glyphs. 4 | /// 5 | /// This widget takes a string and paints it as a series of small dots using a 6 | /// specified style, dot size, spacing, and gradient colors. 7 | class DottedText extends StatelessWidget { 8 | /// The text content to display. 9 | final String text; 10 | 11 | /// The style of the text, including font size, weight, and color. 12 | final TextStyle textStyle; 13 | 14 | /// The diameter of each dot used to form the text. 15 | final double dotSize; 16 | 17 | /// The space between dots. 18 | final double dotSpacing; 19 | 20 | /// The gradient colors applied to the dots. 21 | final List colors; 22 | 23 | /// Creates a [DottedText] widget. 24 | const DottedText({ 25 | super.key, 26 | required this.text, 27 | this.textStyle = const TextStyle( 28 | fontSize: 40, fontWeight: FontWeight.bold, color: Colors.black), 29 | this.dotSize = 2.0, 30 | this.dotSpacing = 3.0, 31 | this.colors = const [Colors.purple, Colors.blue], 32 | }); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return CustomPaint( 37 | painter: _DottedTextPainter( 38 | text: text, 39 | textStyle: textStyle, 40 | dotSize: dotSize, 41 | dotSpacing: dotSpacing, 42 | colors: colors, 43 | ), 44 | ); 45 | } 46 | } 47 | 48 | /// A custom painter that draws text as a series of small dots. 49 | class _DottedTextPainter extends CustomPainter { 50 | final String text; 51 | final TextStyle textStyle; 52 | final double dotSize; 53 | final double dotSpacing; 54 | final List colors; 55 | 56 | _DottedTextPainter({ 57 | required this.text, 58 | required this.textStyle, 59 | required this.dotSize, 60 | required this.dotSpacing, 61 | required this.colors, 62 | }); 63 | 64 | @override 65 | void paint(Canvas canvas, Size size) async { 66 | // Paints the text to an offscreen canvas to extract pixel information. 67 | final textPainter = TextPainter( 68 | text: TextSpan(text: text, style: textStyle), 69 | textDirection: TextDirection.ltr, 70 | )..layout(); 71 | 72 | final ui.PictureRecorder recorder = ui.PictureRecorder(); 73 | final Canvas textCanvas = Canvas(recorder); 74 | textPainter.paint(textCanvas, Offset.zero); 75 | final ui.Picture picture = recorder.endRecording(); 76 | final ui.Image image = picture.toImageSync( 77 | textPainter.width.toInt(), textPainter.height.toInt()); 78 | 79 | final ByteData? data = 80 | await image.toByteData(format: ui.ImageByteFormat.rawRgba); 81 | if (data == null) return; 82 | 83 | final Uint8List bytes = data.buffer.asUint8List(); 84 | final Paint dotPaint = Paint() 85 | ..style = PaintingStyle.fill 86 | ..shader = LinearGradient(colors: colors) 87 | .createShader(Rect.fromLTWH(0, 0, size.width, size.height)); 88 | 89 | // Iterate over image pixels and draw dots where text is present. 90 | for (int y = 0; 91 | y < textPainter.height.toInt(); 92 | y += (dotSpacing + dotSize).toInt()) { 93 | for (int x = 0; 94 | x < textPainter.width.toInt(); 95 | x += (dotSpacing + dotSize).toInt()) { 96 | final int index = (y * textPainter.width.toInt() + x) * 4; 97 | if (index >= bytes.length) continue; 98 | 99 | final int alpha = bytes[index + 3]; 100 | if (alpha > 50) { 101 | canvas.drawCircle( 102 | Offset(x.toDouble(), y.toDouble()), dotSize / 2, dotPaint); 103 | } 104 | } 105 | } 106 | } 107 | 108 | @override 109 | bool shouldRepaint(CustomPainter oldDelegate) => false; 110 | } 111 | -------------------------------------------------------------------------------- /lib/shape/dotted_star.dart: -------------------------------------------------------------------------------- 1 | part of '../dotted_line_flutter.dart'; 2 | 3 | /// A widget that renders a star-shaped dotted pattern using a customizable gradient. 4 | class DottedStar extends StatelessWidget { 5 | /// The gradient colors used to fill the dots. 6 | final List gradientColors; 7 | 8 | /// The overall size of the star. 9 | final double size; 10 | 11 | /// The number of points in the star. 12 | final int points; 13 | 14 | /// The size of each dot forming the star. 15 | final double dotSize; 16 | 17 | /// The spacing between each dot in the star. 18 | final double dotSpacing; 19 | 20 | /// The scaling factor for resizing the star. 21 | final double scaleFactor; 22 | 23 | /// The rotation angle of the star in radians. 24 | final double angle; 25 | 26 | /// Creates a [DottedStar] widget with customizable properties. 27 | const DottedStar({ 28 | super.key, 29 | this.gradientColors = const [Colors.yellow, Colors.orange], 30 | this.size = 50.0, 31 | this.points = 5, 32 | this.dotSize = 3.0, 33 | this.dotSpacing = 5.0, 34 | this.scaleFactor = 1.0, 35 | this.angle = 0.0, 36 | }); 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return Transform.scale( 41 | scale: scaleFactor, 42 | child: Transform.rotate( 43 | angle: angle, // Rotate the star 44 | child: CustomPaint( 45 | painter: _StarPainter( 46 | gradientColors: gradientColors, 47 | points: points, 48 | dotSize: dotSize, 49 | dotSpacing: dotSpacing, 50 | ), 51 | size: Size(size, size), 52 | ), 53 | ), 54 | ); 55 | } 56 | } 57 | 58 | /// A custom painter for rendering a dotted star shape. 59 | class _StarPainter extends CustomPainter { 60 | /// The gradient colors for the dots. 61 | final List gradientColors; 62 | 63 | /// The number of points in the star. 64 | final int points; 65 | 66 | /// The size of each dot forming the star. 67 | final double dotSize; 68 | 69 | /// The spacing between each dot in the star. 70 | final double dotSpacing; 71 | 72 | /// Creates a [_StarPainter] with customizable properties. 73 | _StarPainter({ 74 | required this.gradientColors, 75 | this.points = 5, 76 | this.dotSize = 3.0, 77 | this.dotSpacing = 5.0, 78 | }); 79 | 80 | @override 81 | void paint(Canvas canvas, Size size) { 82 | final Path starPath = _createStarPath( 83 | size.width / 2, 84 | size.height / 2, 85 | size.width / 2, 86 | points, 87 | ); 88 | 89 | final Paint paint = Paint() 90 | ..shader = RadialGradient(colors: gradientColors).createShader( 91 | Rect.fromCircle( 92 | center: Offset(size.width / 2, size.height / 2), 93 | radius: size.width / 2, 94 | ), 95 | ); 96 | 97 | final PathMetrics metrics = starPath.computeMetrics(); 98 | for (final PathMetric metric in metrics) { 99 | double distance = 0.0; 100 | while (distance < metric.length) { 101 | Offset point = metric.getTangentForOffset(distance)!.position; 102 | canvas.drawCircle(point, dotSize / 2, paint); 103 | distance += dotSpacing; 104 | } 105 | } 106 | } 107 | 108 | /// Generates a star path with the given parameters. 109 | Path _createStarPath(double cx, double cy, double radius, int points) { 110 | final Path path = Path(); 111 | final double innerRadius = radius / 2.5; 112 | final double angle = pi / points; 113 | 114 | for (int i = 0; i < points * 2; i++) { 115 | double r = i.isEven ? radius : innerRadius; 116 | double x = cx + r * cos(i * angle); 117 | double y = cy + r * sin(i * angle); 118 | if (i == 0) { 119 | path.moveTo(x, y); 120 | } else { 121 | path.lineTo(x, y); 122 | } 123 | } 124 | path.close(); 125 | return path; 126 | } 127 | 128 | @override 129 | bool shouldRepaint(CustomPainter oldDelegate) => false; 130 | } 131 | -------------------------------------------------------------------------------- /lib/shape/dotted_cube.dart: -------------------------------------------------------------------------------- 1 | part of '../dotted_line_flutter.dart'; 2 | 3 | /// A widget that displays a 3D dotted cube with customizable properties. 4 | class DottedCube extends StatelessWidget { 5 | /// The size of the cube. 6 | final double size; 7 | 8 | /// The size of each dot in the cube. 9 | final double dotSize; 10 | 11 | /// The spacing between dots. 12 | final double dotSpacing; 13 | 14 | /// The scaling factor for the cube. 15 | final double scaleFactor; 16 | 17 | /// The rotation angle of the cube. 18 | final double angle; 19 | 20 | /// The gradient colors for the cube. 21 | final List gradientColors; 22 | 23 | /// Creates a [DottedCube] widget with customizable properties. 24 | const DottedCube({ 25 | super.key, 26 | this.size = 100.0, 27 | this.dotSize = 4.0, 28 | this.dotSpacing = 8.0, 29 | this.scaleFactor = 1.0, 30 | this.angle = 0.0, 31 | this.gradientColors = const [Colors.blue, Colors.purple], 32 | }); 33 | 34 | @override 35 | Widget build(BuildContext context) { 36 | return Transform.scale( 37 | scale: scaleFactor, 38 | child: Transform.rotate( 39 | angle: angle, 40 | child: CustomPaint( 41 | painter: _CubePainter( 42 | dotSize: dotSize, 43 | dotSpacing: dotSpacing, 44 | gradientColors: gradientColors, 45 | ), 46 | size: Size(size, size), 47 | ), 48 | ), 49 | ); 50 | } 51 | } 52 | 53 | /// A custom painter that draws a 3D dotted cube. 54 | class _CubePainter extends CustomPainter { 55 | /// The size of each dot in the cube. 56 | final double dotSize; 57 | 58 | /// The spacing between dots. 59 | final double dotSpacing; 60 | 61 | /// The gradient colors for the cube. 62 | final List gradientColors; 63 | 64 | /// Creates a [_CubePainter] with the given properties. 65 | _CubePainter({ 66 | required this.dotSize, 67 | required this.dotSpacing, 68 | required this.gradientColors, 69 | }); 70 | 71 | @override 72 | void paint(Canvas canvas, Size size) { 73 | final Paint paint = Paint() 74 | ..shader = LinearGradient( 75 | colors: gradientColors, 76 | ).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); 77 | 78 | // Define cube points 79 | final Offset p1 = Offset(size.width * 0.2, size.height * 0.2); 80 | final Offset p2 = Offset(size.width * 0.8, size.height * 0.2); 81 | final Offset p3 = Offset(size.width * 0.8, size.height * 0.8); 82 | final Offset p4 = Offset(size.width * 0.2, size.height * 0.8); 83 | 84 | final Offset p5 = Offset(size.width * 0.4, size.height * 0.0); 85 | final Offset p6 = Offset(size.width * 1.0, size.height * 0.0); 86 | final Offset p7 = Offset(size.width * 1.0, size.height * 0.6); 87 | final Offset p8 = Offset(size.width * 0.4, size.height * 0.6); 88 | 89 | // Draw dotted cube edges 90 | _drawDottedLine(canvas, paint, p1, p2); 91 | _drawDottedLine(canvas, paint, p2, p3); 92 | _drawDottedLine(canvas, paint, p3, p4); 93 | _drawDottedLine(canvas, paint, p4, p1); 94 | 95 | _drawDottedLine(canvas, paint, p1, p5); 96 | _drawDottedLine(canvas, paint, p2, p6); 97 | _drawDottedLine(canvas, paint, p3, p7); 98 | _drawDottedLine(canvas, paint, p4, p8); 99 | 100 | _drawDottedLine(canvas, paint, p5, p6); 101 | _drawDottedLine(canvas, paint, p6, p7); 102 | _drawDottedLine(canvas, paint, p7, p8); 103 | _drawDottedLine(canvas, paint, p8, p5); 104 | } 105 | 106 | /// Draws a dotted line between [start] and [end] using [paint]. 107 | void _drawDottedLine(Canvas canvas, Paint paint, Offset start, Offset end) { 108 | final double distance = (end - start).distance; 109 | final int dotCount = (distance / (dotSize + dotSpacing)).floor(); 110 | final Offset direction = (end - start) / distance; 111 | 112 | for (int i = 0; i < dotCount; i++) { 113 | Offset dotPosition = 114 | start + direction * i.toDouble() * (dotSize + dotSpacing); 115 | canvas.drawCircle(dotPosition, dotSize / 2, paint); 116 | } 117 | } 118 | 119 | @override 120 | bool shouldRepaint(CustomPainter oldDelegate) => false; 121 | } 122 | -------------------------------------------------------------------------------- /lib/shape/dotted_line.dart: -------------------------------------------------------------------------------- 1 | part of '../dotted_line_flutter.dart'; 2 | 3 | /// A custom widget that renders a dotted line with optional gradient, shadow, 4 | /// and configurable spacing. 5 | class DottedLine extends StatelessWidget { 6 | /// A list of colors used to create a gradient effect on the dotted line. 7 | final List colors; 8 | 9 | /// The thickness of the line (height for horizontal, width for vertical). 10 | final double lineThickness; 11 | 12 | /// The gap between dashes. 13 | final double dashGap; 14 | 15 | /// The width of each dash. 16 | final double dashWidth; 17 | 18 | /// The total height of the widget (applicable for horizontal lines). 19 | final double height; 20 | 21 | /// The direction of the dotted line (horizontal or vertical). 22 | final Axis axis; 23 | 24 | /// The shadow color applied to the dashes. 25 | final Color shadowColor; 26 | 27 | /// The blur radius of the shadow. 28 | final double shadowBlurRadius; 29 | 30 | /// Creates a `DottedLine` widget with customizable properties. 31 | const DottedLine({ 32 | super.key, 33 | this.colors = const [Colors.purple], 34 | this.lineThickness = 2.0, 35 | this.dashGap = 5.0, 36 | this.height = 2.0, 37 | this.dashWidth = 5.0, 38 | this.axis = Axis.horizontal, 39 | this.shadowColor = Colors.black54, 40 | this.shadowBlurRadius = 4.0, 41 | }); 42 | 43 | @override 44 | Widget build(BuildContext context) { 45 | return CustomPaint( 46 | painter: _DottedLinePainter( 47 | colors: colors.isEmpty ? [Colors.purple] : colors, 48 | lineThickness: lineThickness, 49 | dashGap: dashGap, 50 | dashWidth: dashWidth, 51 | axis: axis, 52 | shadowColor: shadowColor, 53 | shadowBlurRadius: shadowBlurRadius, 54 | ), 55 | size: axis == Axis.horizontal 56 | ? Size(double.infinity, height) 57 | : Size(1, height), 58 | ); 59 | } 60 | } 61 | 62 | /// A custom painter that draws a dotted line with optional gradient and shadow. 63 | class _DottedLinePainter extends CustomPainter { 64 | final List colors; 65 | final double lineThickness; 66 | final double dashGap; 67 | final double dashWidth; 68 | final Axis axis; 69 | final Color shadowColor; 70 | final double shadowBlurRadius; 71 | 72 | _DottedLinePainter({ 73 | required this.colors, 74 | required this.lineThickness, 75 | required this.dashGap, 76 | required this.dashWidth, 77 | required this.axis, 78 | required this.shadowColor, 79 | required this.shadowBlurRadius, 80 | }); 81 | 82 | @override 83 | void paint(Canvas canvas, Size size) { 84 | final Paint paint = Paint() 85 | ..style = PaintingStyle.stroke 86 | ..strokeWidth = lineThickness 87 | ..strokeCap = StrokeCap.round; 88 | 89 | // Shadow Paint 90 | final Paint shadowPaint = Paint() 91 | ..color = shadowColor 92 | ..strokeWidth = lineThickness 93 | ..strokeCap = StrokeCap.round 94 | ..maskFilter = MaskFilter.blur(BlurStyle.normal, shadowBlurRadius); 95 | 96 | // Apply gradient shader if multiple colors are provided 97 | if (colors.length > 1) { 98 | paint.shader = LinearGradient( 99 | colors: colors, 100 | begin: axis == Axis.horizontal 101 | ? Alignment.centerLeft 102 | : Alignment.topCenter, 103 | end: axis == Axis.horizontal 104 | ? Alignment.centerRight 105 | : Alignment.bottomCenter, 106 | ).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); 107 | } else { 108 | paint.color = colors.first; 109 | } 110 | 111 | double startPos = 0.0; 112 | bool isGap = false; 113 | 114 | while (startPos < (axis == Axis.horizontal ? size.width : size.height)) { 115 | if (!isGap) { 116 | final Offset startOffset = axis == Axis.horizontal 117 | ? Offset(startPos, size.height / 2) 118 | : Offset(size.width / 2, startPos); 119 | final Offset endOffset = axis == Axis.horizontal 120 | ? Offset(startPos + dashWidth, size.height / 2) 121 | : Offset(size.width / 2, startPos + dashWidth); 122 | 123 | // Draw shadow layer with a slight offset 124 | canvas.drawLine( 125 | startOffset.translate(2, 2), 126 | endOffset.translate(2, 2), 127 | shadowPaint, 128 | ); 129 | 130 | // Draw actual dotted line segment 131 | canvas.drawLine(startOffset, endOffset, paint); 132 | } 133 | startPos += isGap ? dashGap : dashWidth; 134 | isGap = !isGap; 135 | } 136 | } 137 | 138 | @override 139 | bool shouldRepaint(CustomPainter oldDelegate) => false; 140 | } 141 | -------------------------------------------------------------------------------- /lib/shape/dotted_widget.dart: -------------------------------------------------------------------------------- 1 | part of '../dotted_line_flutter.dart'; 2 | 3 | /// A custom widget that draws a dotted border around its child. 4 | class DottedWidget extends StatelessWidget { 5 | /// The child widget inside the dotted border. 6 | final Widget? child; 7 | 8 | /// The border radius of the dotted border. 9 | final double borderRadius; 10 | 11 | /// The colors of the dotted border. 12 | final List colors; 13 | 14 | /// The thickness of the dotted lines. 15 | final double lineThickness; 16 | 17 | /// The gap between dashes in the dotted border. 18 | final double dashGap; 19 | 20 | /// The width of each dash in the dotted border. 21 | final double dashWidth; 22 | 23 | /// The direction of the dashes (horizontal or vertical). 24 | final Axis axis; 25 | 26 | /// The shadow color of the dotted border. 27 | final Color shadowColor; 28 | 29 | /// The blur radius for the shadow effect. 30 | final double shadowBlurRadius; 31 | 32 | /// The width of the container. 33 | final double width; 34 | 35 | /// The height of the container. 36 | final double height; 37 | 38 | /// The shape of the border (rectangle or circle). 39 | final BoxShape shape; 40 | 41 | /// Creates a [DottedWidget] with customizable properties. 42 | const DottedWidget({ 43 | super.key, 44 | this.child, 45 | this.borderRadius = 10.0, 46 | this.colors = const [Colors.purple], 47 | this.lineThickness = 2.0, 48 | this.dashGap = 5.0, 49 | this.dashWidth = 5.0, 50 | this.axis = Axis.horizontal, 51 | this.shadowColor = Colors.black54, 52 | this.shadowBlurRadius = 4.0, 53 | this.width = 100.0, 54 | this.height = 50.0, 55 | this.shape = BoxShape.rectangle, 56 | }); 57 | 58 | @override 59 | Widget build(BuildContext context) { 60 | return CustomPaint( 61 | painter: _DottedBorderPainter( 62 | borderRadius: borderRadius, 63 | colors: colors, 64 | lineThickness: lineThickness, 65 | dashGap: dashGap, 66 | dashWidth: dashWidth, 67 | axis: axis, 68 | shadowColor: shadowColor, 69 | shadowBlurRadius: shadowBlurRadius, 70 | shape: shape, 71 | ), 72 | child: Container( 73 | width: width, 74 | height: height, 75 | alignment: Alignment.center, 76 | child: child, 77 | ), 78 | ); 79 | } 80 | } 81 | 82 | /// A custom painter that draws a dotted border. 83 | class _DottedBorderPainter extends CustomPainter { 84 | final double borderRadius; 85 | final List colors; 86 | final double lineThickness; 87 | final double dashGap; 88 | final double dashWidth; 89 | final Axis axis; 90 | final Color shadowColor; 91 | final double shadowBlurRadius; 92 | final BoxShape shape; 93 | 94 | /// Creates a painter to draw a dotted border. 95 | _DottedBorderPainter({ 96 | required this.borderRadius, 97 | required this.colors, 98 | required this.lineThickness, 99 | required this.dashGap, 100 | required this.dashWidth, 101 | required this.axis, 102 | required this.shadowColor, 103 | required this.shadowBlurRadius, 104 | required this.shape, 105 | }); 106 | 107 | @override 108 | void paint(Canvas canvas, Size size) { 109 | Paint paint = Paint() 110 | ..strokeWidth = lineThickness 111 | ..style = PaintingStyle.stroke 112 | ..shader = LinearGradient(colors: colors) 113 | .createShader(Rect.fromLTWH(0, 0, size.width, size.height)) 114 | ..maskFilter = MaskFilter.blur(BlurStyle.normal, shadowBlurRadius); 115 | 116 | Path path; 117 | if (shape == BoxShape.circle) { 118 | path = Path() 119 | ..addOval(Rect.fromCircle( 120 | center: Offset(size.width / 2, size.height / 2), 121 | radius: size.width / 2)); 122 | } else { 123 | path = Path() 124 | ..addRRect(RRect.fromRectAndRadius( 125 | Rect.fromLTWH(0, 0, size.width, size.height), 126 | Radius.circular(borderRadius))); 127 | } 128 | 129 | drawDottedPath(canvas, paint, path); 130 | } 131 | 132 | /// Draws a dotted pattern along the given path. 133 | void drawDottedPath(Canvas canvas, Paint paint, Path path) { 134 | PathMetrics pathMetrics = path.computeMetrics(); 135 | for (PathMetric pathMetric in pathMetrics) { 136 | double distance = 0.0; 137 | while (distance < pathMetric.length) { 138 | Tangent? tangent = pathMetric.getTangentForOffset(distance); 139 | if (tangent != null) { 140 | canvas.drawCircle(tangent.position, lineThickness / 2, paint); 141 | } 142 | distance += dashWidth + dashGap; 143 | } 144 | } 145 | } 146 | 147 | @override 148 | bool shouldRepaint(CustomPainter oldDelegate) => false; 149 | } 150 | -------------------------------------------------------------------------------- /example/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:dotted_line_flutter/dotted_line_flutter.dart'; 3 | import 'package:flutter/material.dart'; 4 | 5 | class DottedLineExample extends StatelessWidget { 6 | const DottedLineExample({super.key}); 7 | 8 | @override 9 | Widget build(BuildContext context) { 10 | return Scaffold( 11 | appBar: AppBar( 12 | title: const Text( 13 | 'Flutter Dotted Examples', 14 | style: TextStyle(color: Colors.white), 15 | ), 16 | backgroundColor: Colors.black, 17 | flexibleSpace: Container( 18 | decoration: const BoxDecoration( 19 | gradient: LinearGradient( 20 | colors: [Colors.blue, Colors.purple], // Gradient colors 21 | begin: Alignment.topLeft, 22 | end: Alignment.bottomRight, 23 | ), 24 | ), 25 | ), 26 | ), 27 | backgroundColor: Colors.white, 28 | body: const SingleChildScrollView( 29 | child: Column( 30 | children: [ 31 | SizedBox( 32 | height: 30, 33 | ), 34 | DottedText( 35 | text: "Flutter", 36 | textStyle: TextStyle(fontSize: 80, fontWeight: FontWeight.bold), 37 | dotSize: 4.0, 38 | dotSpacing: 3.0, 39 | colors: [Colors.red, Colors.orange], 40 | ), 41 | DottedLine( 42 | axis: Axis.horizontal, 43 | lineThickness: 3, 44 | shadowColor: Colors.blueAccent, 45 | shadowBlurRadius: 40, 46 | dashGap: 5, 47 | colors: [ 48 | Colors.amberAccent, 49 | Colors.deepPurple, 50 | ], 51 | ), 52 | SizedBox( 53 | height: 20, 54 | ), 55 | DottedWidget( 56 | width: 120, 57 | height: 50, 58 | borderRadius: 20, 59 | colors: [Colors.blue, Colors.green], 60 | dashWidth: 6, 61 | shadowBlurRadius: 0, 62 | dashGap: 4, 63 | child: Text('Hello', style: TextStyle(fontSize: 18)), 64 | ), 65 | SizedBox(height: 20), 66 | Row( 67 | mainAxisAlignment: MainAxisAlignment.center, 68 | children: [ 69 | DottedWidget( 70 | width: 100, 71 | height: 100, 72 | lineThickness: 3, 73 | dashWidth: 3, 74 | borderRadius: 3, 75 | shadowBlurRadius: 0, 76 | colors: [Colors.red, Colors.orange], 77 | shape: BoxShape.circle, 78 | child: Icon(Icons.person, size: 50), 79 | ), 80 | SizedBox(width: 20), 81 | DottedWidget( 82 | width: 100, 83 | height: 100, 84 | colors: [Colors.red, Colors.orange], 85 | shape: BoxShape.circle, 86 | child: Icon(Icons.account_circle, size: 50), 87 | ), 88 | ], 89 | ), 90 | DottedStar( 91 | size: 100, // Base size of the star 92 | points: 5, // 5-point star 93 | dotSize: 4, // Dot size 94 | dotSpacing: 6, // Dot spacing 95 | scaleFactor: 1, // Scale up by 1.5x 96 | angle: pi / 1.4, 97 | gradientColors: [Colors.blue, Colors.purple], // Gradient color 98 | ), 99 | Row( 100 | crossAxisAlignment: CrossAxisAlignment.center, 101 | mainAxisAlignment: MainAxisAlignment.center, 102 | children: [ 103 | DottedLine( 104 | axis: Axis.vertical, 105 | lineThickness: 3, 106 | height: 60, 107 | shadowColor: Colors.blueAccent, 108 | shadowBlurRadius: 40, 109 | dashGap: 5, 110 | colors: [ 111 | Colors.amberAccent, 112 | Colors.deepPurple, 113 | ], 114 | ), 115 | SizedBox( 116 | width: 10, 117 | ), 118 | DottedLine( 119 | axis: Axis.vertical, 120 | lineThickness: 3, 121 | height: 60, 122 | dashGap: 6, 123 | dashWidth: 6, 124 | colors: [Colors.red, Colors.blue], 125 | shadowColor: Colors.black, 126 | shadowBlurRadius: 10.0, 127 | ), 128 | ], 129 | ), 130 | SizedBox( 131 | height: 20, 132 | ), 133 | DottedLine( 134 | axis: Axis.horizontal, 135 | lineThickness: 3, 136 | dashGap: 6, 137 | dashWidth: 6, 138 | colors: [Colors.red, Colors.blue], // ✅ Gradient Dotted Line 139 | shadowColor: Colors.red, // ✅ Dark Shadow 140 | shadowBlurRadius: 6.0, // ✅ Stronger Blur Effect 141 | ), 142 | SizedBox(height: 20), 143 | Row( 144 | children: [ 145 | DottedShape( 146 | shapeType: ShapeType.crescent, dotColor: Color(0xff02343F)), 147 | SizedBox( 148 | width: 20, 149 | ), 150 | DottedShape( 151 | shapeType: ShapeType.cylinder, 152 | dotColor: Color(0xffFEE715), 153 | ), 154 | SizedBox(width: 20), 155 | DottedShape( 156 | shapeType: ShapeType.heart, 157 | dotColor: Color(0xfff101820), 158 | ), 159 | ], 160 | ), 161 | SizedBox(height: 20), 162 | Row( 163 | children: [ 164 | DottedShape(shapeType: ShapeType.hexagon, dotColor: Colors.red), 165 | SizedBox(width: 20), 166 | DottedShape( 167 | shapeType: ShapeType.hexagram, dotColor: Colors.red), 168 | SizedBox(width: 20), 169 | DottedShape(shapeType: ShapeType.oval, dotColor: Colors.red), 170 | ], 171 | ), 172 | SizedBox(height: 20), 173 | Row( 174 | children: [ 175 | DottedShape( 176 | shapeType: ShapeType.pentagon, dotColor: Colors.red), 177 | SizedBox(width: 20), 178 | DottedShape(shapeType: ShapeType.rhombus, dotColor: Colors.red), 179 | SizedBox(width: 20), 180 | DottedShape( 181 | shapeType: ShapeType.semicircle, dotColor: Colors.red), 182 | ], 183 | ), 184 | SizedBox(height: 20), 185 | Row( 186 | children: [ 187 | DottedShape( 188 | shapeType: ShapeType.triangle, dotColor: Colors.red), 189 | SizedBox(width: 20), 190 | DottedShape( 191 | shapeType: ShapeType.triquetra, dotColor: Colors.red), 192 | SizedBox(width: 20), 193 | ], 194 | ), 195 | SizedBox(height: 10), 196 | DottedCube( 197 | size: 120, // Cube size 198 | dotSize: 4, // Dot size 199 | dotSpacing: 6, // Dot spacing 200 | scaleFactor: 1.2, // Scale the cube 201 | angle: pi / 4, // Rotate the cube (30 degrees) 202 | gradientColors: [Colors.red, Colors.green], // Gradient color 203 | ), 204 | SizedBox(height: 50), 205 | ], 206 | ), 207 | ), 208 | ); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /lib/shape/dotted_shapes.dart: -------------------------------------------------------------------------------- 1 | part of '../dotted_line_flutter.dart'; 2 | 3 | /// Enum representing different shape types. 4 | /// 5 | /// This enum defines various geometric shapes that can be used 6 | /// in different contexts such as UI design, graphics rendering, 7 | /// and mathematical operations. 8 | enum ShapeType { 9 | /// A cone shape. 10 | cone, 11 | 12 | /// A cylinder shape. 13 | cylinder, 14 | 15 | /// An oval shape. 16 | oval, 17 | 18 | /// A triangle shape. 19 | triangle, 20 | 21 | /// A hexagon shape. 22 | hexagon, 23 | 24 | /// A pentagon shape. 25 | pentagon, 26 | 27 | /// A hexagram shape. 28 | hexagram, 29 | 30 | /// A rhombus shape. 31 | rhombus, 32 | 33 | /// A heart shape. 34 | heart, 35 | 36 | /// A triquetra shape. 37 | triquetra, 38 | 39 | /// A semicircle shape. 40 | semicircle, 41 | 42 | /// A crescent shape. 43 | crescent, 44 | } 45 | 46 | /// A widget that represents a dotted shape based on a given [ShapeType]. 47 | /// 48 | /// This widget allows customization of the shape's size, dot size, spacing, 49 | /// and color. 50 | class DottedShape extends StatelessWidget { 51 | /// The overall size of the shape. 52 | final double size; 53 | 54 | /// The size of individual dots forming the shape. 55 | final double dotSize; 56 | 57 | /// The spacing between dots in the shape. 58 | final double dotSpacing; 59 | 60 | /// The type of shape to be drawn using dots. 61 | final ShapeType shapeType; 62 | 63 | /// The color of the dots forming the shape. 64 | final Color dotColor; 65 | 66 | /// Creates a [DottedShape] widget. 67 | /// 68 | /// [shapeType] is required to define the shape to be drawn. 69 | /// [size] defines the overall size of the shape. 70 | /// [dotSize] controls the size of each individual dot. 71 | /// [dotSpacing] determines the spacing between dots. 72 | /// [dotColor] sets the color of the dots. 73 | const DottedShape({ 74 | super.key, 75 | required this.shapeType, 76 | this.size = 100.0, 77 | this.dotSize = 4.0, 78 | this.dotSpacing = 6.0, 79 | this.dotColor = Colors.black, 80 | }); 81 | 82 | @override 83 | Widget build(BuildContext context) { 84 | return CustomPaint( 85 | painter: _DottedShapePainter( 86 | shapeType: shapeType, 87 | dotSize: dotSize, 88 | dotSpacing: dotSpacing, 89 | dotColor: dotColor, 90 | ), 91 | size: Size(size, size), 92 | ); 93 | } 94 | } 95 | 96 | /// Custom painter that draws the dotted shape. 97 | class _DottedShapePainter extends CustomPainter { 98 | final ShapeType shapeType; 99 | final double dotSize; 100 | final double dotSpacing; 101 | final Color dotColor; 102 | 103 | _DottedShapePainter({ 104 | required this.shapeType, 105 | required this.dotSize, 106 | required this.dotSpacing, 107 | required this.dotColor, 108 | }); 109 | 110 | @override 111 | void paint(Canvas canvas, Size size) { 112 | Paint paint = Paint()..color = dotColor; 113 | Path path = getShapePath(size); 114 | drawDottedPath(canvas, paint, path); 115 | } 116 | 117 | /// Returns the path of the specified shape. 118 | Path getShapePath(Size size) { 119 | switch (shapeType) { 120 | case ShapeType.cone: 121 | return _createConePath(size); 122 | case ShapeType.cylinder: 123 | return _createCylinderPath(size); 124 | case ShapeType.oval: 125 | return _createOvalPath(size); 126 | case ShapeType.triangle: 127 | return _createPolygonPath(size, 3); 128 | case ShapeType.hexagon: 129 | return _createPolygonPath(size, 6); 130 | case ShapeType.pentagon: 131 | return _createPolygonPath(size, 5); 132 | case ShapeType.hexagram: 133 | return _createHexagramPath(size); 134 | case ShapeType.rhombus: 135 | return _createRhombusPath(size); 136 | case ShapeType.heart: 137 | return _createHeartPath(size); 138 | case ShapeType.triquetra: 139 | return _createTriquetraPath(size); 140 | case ShapeType.semicircle: 141 | return _createSemiCirclePath(size); 142 | case ShapeType.crescent: 143 | return _createCrescentPath(size); 144 | } 145 | } 146 | 147 | /// Draws the dotted path based on the computed path metrics. 148 | void drawDottedPath(Canvas canvas, Paint paint, Path path) { 149 | PathMetrics pathMetrics = path.computeMetrics(); 150 | for (PathMetric pathMetric in pathMetrics) { 151 | double distance = 0.0; 152 | while (distance < pathMetric.length) { 153 | Tangent? tangent = pathMetric.getTangentForOffset(distance); 154 | if (tangent != null) { 155 | canvas.drawCircle(tangent.position, dotSize / 2, paint); 156 | } 157 | distance += dotSize + dotSpacing; 158 | } 159 | } 160 | } 161 | 162 | /// Creates a hexagram path. 163 | Path _createHexagramPath(Size size) { 164 | Path path = _createPolygonPath(size, 6); 165 | path.addPath(_createPolygonPath(size, 6)..shift(Offset(0, size.height / 6)), 166 | Offset.zero); 167 | return path; 168 | } 169 | 170 | /// Creates a Rhombus Path. 171 | Path _createRhombusPath(Size size) { 172 | Path path = Path(); 173 | path.moveTo(size.width / 2, 0); 174 | path.lineTo(size.width, size.height / 2); 175 | path.lineTo(size.width / 2, size.height); 176 | path.lineTo(0, size.height / 2); 177 | path.close(); 178 | return path; 179 | } 180 | 181 | /// Creates a Triquetra Path. 182 | Path _createTriquetraPath(Size size) { 183 | Path path = Path(); 184 | double radius = size.width / 3; 185 | for (int i = 0; i < 3; i++) { 186 | path.addArc( 187 | Rect.fromCircle( 188 | center: Offset(size.width / 2, size.height / 2), radius: radius), 189 | i * 2 * pi / 3, 190 | pi); 191 | } 192 | return path; 193 | } 194 | 195 | /// Creates a cone-shaped path. 196 | Path _createConePath(Size size) { 197 | Path path = Path(); 198 | path.moveTo(size.width / 2, 0); 199 | path.lineTo(size.width, size.height); 200 | path.lineTo(0, size.height); 201 | path.close(); 202 | return path; 203 | } 204 | 205 | /// Creates a cylinder-shaped path. 206 | Path _createCylinderPath(Size size) { 207 | Path path = Path(); 208 | path.addOval(Rect.fromLTRB(0, 0, size.width, size.height / 4)); 209 | path.moveTo(0, size.height / 8); 210 | path.lineTo(0, size.height * 0.9); 211 | path.lineTo(size.width, size.height * 0.9); 212 | path.lineTo(size.width, size.height / 8); 213 | path.close(); 214 | return path; 215 | } 216 | 217 | /// Creates an oval-shaped path. 218 | Path _createOvalPath(Size size) { 219 | return Path()..addOval(Rect.fromLTRB(0, 0, size.width, size.height)); 220 | } 221 | 222 | /// Creates a polygon-shaped path (triangle, hexagon, pentagon, etc.). 223 | Path _createPolygonPath(Size size, int sides) { 224 | Path path = Path(); 225 | double radius = size.width / 2; 226 | double angle = (2 * pi) / sides; 227 | 228 | for (int i = 0; i < sides; i++) { 229 | double x = size.width / 2 + radius * cos(i * angle); 230 | double y = size.height / 2 + radius * sin(i * angle); 231 | if (i == 0) { 232 | path.moveTo(x, y); 233 | } else { 234 | path.lineTo(x, y); 235 | } 236 | } 237 | path.close(); 238 | return path; 239 | } 240 | 241 | /// Creates a heart-shaped path. 242 | Path _createHeartPath(Size size) { 243 | Path path = Path(); 244 | path.moveTo(size.width / 2, size.height * 0.75); 245 | path.quadraticBezierTo(size.width, size.height * 0.2, size.width / 2, 0); 246 | path.quadraticBezierTo( 247 | 0, size.height * 0.2, size.width / 2, size.height * 0.75); 248 | path.close(); 249 | return path; 250 | } 251 | 252 | /// Creates a semicircle-shaped path. 253 | Path _createSemiCirclePath(Size size) { 254 | return Path()..addArc(Rect.fromLTRB(0, 0, size.width, size.height), pi, pi); 255 | } 256 | 257 | /// Creates a crescent-shaped path. 258 | Path _createCrescentPath(Size size) { 259 | Path path = Path(); 260 | path.addOval(Rect.fromLTRB(0, 0, size.width, size.height)); 261 | path.addOval( 262 | Rect.fromLTRB(size.width / 4, 0, size.width * 1.1, size.height)); 263 | return path; 264 | } 265 | 266 | @override 267 | bool shouldRepaint(CustomPainter oldDelegate) => false; 268 | } 269 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dotted Line Flutter Package 2 | 3 | ![Logo](https://blogger.googleusercontent.com/img/a/AVvXsEh-3WixyUqbulBnLmtjCYHybJV1ZbhNjlM_pkif4BllCI-PQ5_YIaZvcFF8GUG8qrykJIq9QhdGIcW9LlGijUNt3wShuQIVa0JhnxnazJ64iApAKiN9CAQOLWszZQVQZYyrTuNPkSDxTbf_cvn20gvB4oaBePOP4wAqGl3YUHBAJ-pwQzNTeh-ERbZj81g=w280-h280-s-no) 4 | 5 | A highly customizable Flutter package for drawing **dotted, dashed, and gradient lines** in both horizontal and vertical directions. It also supports **shadow effects** and **multiple shapes**. 6 | 7 | ## ✨ Features 8 | 9 | ✅ **Dotted and Dashed Lines** 10 | ✅ **Gradient Color Support** 11 | ✅ **Customizable Dash Width & Gap** 12 | ✅ **Horizontal & Vertical Orientation** 13 | ✅ **Shadow Effect for Depth** 14 | ✅ **More Shapes (Star, Circle, etc.)** 15 | ✅ **Star Shape** 16 | ✅ **Circle Dotted Line** 17 | ✅ **Custom Dash Shapes** 18 | ✅ **Patterned Dashes (Short-Long)** 19 | 20 | 21 | ## 📦 Installation 22 | 23 | Add this to your `pubspec.yaml` file: 24 | 25 | ```yaml 26 | dependencies: 27 | dotted_line_flutter: latest_version 28 | ``` 29 | 30 | Then run: 31 | 32 | ```sh 33 | flutter pub get 34 | ``` 35 | 36 | ## 🛠 Usage 37 | 38 | ### Basic Dotted Line 39 | 40 | ```dart 41 | DottedLine( 42 | axis: Axis.horizontal, 43 | lineThickness: 2, 44 | dashGap: 4, 45 | dashWidth: 6, 46 | colors: [Colors.red, Colors.blue], // Gradient Support 47 | ); 48 | ``` 49 | 50 | ### Vertical Dotted Line 51 | 52 | ```dart 53 | DottedLine( 54 | axis: Axis.vertical, 55 | lineThickness: 3, 56 | dashGap: 5, 57 | colors: [Colors.green], // Single color 58 | ); 59 | ``` 60 | 61 | ### Shadow Effect 62 | 63 | ```dart 64 | DottedLine( 65 | axis: Axis.horizontal, 66 | lineThickness: 3, 67 | dashGap: 6, 68 | colors: [Colors.orange, Colors.purple], 69 | shadowColor: Colors.black, 70 | shadowBlurRadius: 10.0, 71 | ); 72 | ``` 73 | 74 | 75 | ## 🖼 Screenshot 1 76 | ![App Screenshot 1](https://blogger.googleusercontent.com/img/a/AVvXsEhKbsx8TyRbw6zAa1XXLBm4A0DLz-D4Q50La6gM3keCtSACHWF7AoWbsIEqCZWz4PMxeNBUKjCtlrTGDkSGfZskSca1623kAEnAjOwAlzBpo6u9YIdoSdFpXi-xdUeGY44AX6T4ZSppCEk5eZOKA3HL20JkzoWPZ-TsGSsAbJ8vUPN05djwm1zbc6n2daw=w329-h705-s-no) 77 | 78 | ## 🖼 Screenshot 2 79 | ![App Screenshot 2](https://lh3.googleusercontent.com/pw/AIL4fc84TDXjhTMGLf2XqW52SAEyY8-40tXf-fo75gPQGfkCaJ7P2Sne8GhqmbFaghr5r1mD1v2_y1cq0mzMkPuhF2L3H8vw8j8qZ9HRuuJ5vI5tFCFC1QUjzoARck1UpHO8LaXmE8JjoXwx4ORZbXg3rN2S=w329-h705-s-no) 80 | 81 | ## 🖼 Screenshot 3 82 | ![App Screenshot 3](https://blogger.googleusercontent.com/img/a/AVvXsEgNqxxUUx24JETdbL6W6IJpboXI6UPWu4bi7jKxVQerb_BbaUBSD2qeR96TrfRUL_BWkKw5UeqSAgO9hUqpCR1grpy0odS2-3fMQBpzCp9hZu6kvM1-x-ykGdecQbw8BEjekOUTu4_J0L8w5m1ddeqN8RsjPFbG9hLrhMC2pgGtEqFKnlBRt5VnYHm1INM=w329-h705-s-no) 83 | 84 | ## 🖼 Screenshot 4 85 | ![App Screenshot 4](https://blogger.googleusercontent.com/img/a/AVvXsEhOt5uR0JkTtg5zGQAgq2tGq1FrevY46h9yASWc292WwGSwsSogH24jbxywquUxz1BdR6CDtZ4m1b6k7FoTI0g8wbzdt-0l2d_n1wGK-KFEfkvg0jxAxwBSjJ2-wtgVbQBb6uyWNCKV7zXc1m6Jb3hPHOVp2xX5mC0Xo7OxE2yGfoFsNkK8vHcLcNrUwQA=w329-h705-s-no) 86 | 87 | 88 | 89 | # DottedCube Widget 90 | 91 | ## Usage 92 | 93 | ### Parameters 94 | 95 | | Parameter | Default | Description | 96 | |-----------------|--------------------------------|-----------------------------------------------------| 97 | | `size` | `100.0` | The overall size of the cube. | 98 | | `dotSize` | `4.0` | The size of each individual dot. | 99 | | `dotSpacing` | `8.0` | The spacing between dots. | 100 | | `scaleFactor` | `1.0` | The scale factor to resize the widget. | 101 | | `angle` | `0.0` | The rotation angle of the cube. | 102 | | `gradientColors`| `[Colors.blue, Colors.purple]` | The gradient colors used for the dots. | 103 | 104 | The `DottedCube` widget can be used without parameters. 105 | 106 | ```dart 107 | import 'package:flutter/material.dart'; 108 | 109 | DottedCube() 110 | ``` 111 | 112 | You can also customize it by specifying parameters. 113 | 114 | ```dart 115 | import 'package:flutter/material.dart'; 116 | 117 | DottedCube( 118 | size: 120.0, 119 | dotSize: 5.0, 120 | dotSpacing: 10.0, 121 | scaleFactor: 1.2, 122 | angle: 0.5, 123 | gradientColors: [Colors.red, Colors.orange], 124 | ) 125 | ``` 126 | 127 | 128 | # DottedLine Widget 129 | 130 | A Flutter widget to create a customizable dotted line with gradient colors, shadow effects, and adjustable spacing. 131 | 132 | ## Features 133 | - Supports horizontal and vertical orientation. 134 | - Customizable dash width, gap size, and line thickness. 135 | - Gradient color support. 136 | - Shadow effects for a better visual appearance. 137 | 138 | ## Usage 139 | 140 | ### Default Usage 141 | This widget can be used without parameters for a simple dotted line. 142 | 143 | ```dart 144 | import 'package:dotted_line_flutter/dotted_line.dart'; 145 | 146 | DottedLine() 147 | ``` 148 | 149 | ### Custom Usage 150 | You can customize the dotted line by specifying various parameters: 151 | 152 | ```dart 153 | import 'package:dotted_line_flutter/dotted_line.dart'; 154 | 155 | DottedLine( 156 | colors: [Colors.blue, Colors.green], 157 | lineThickness: 2.0, 158 | dashGap: 6.0, 159 | dashWidth: 8.0, 160 | height: 3.0, 161 | axis: Axis.horizontal, 162 | shadowColor: Colors.black38, 163 | shadowBlurRadius: 5.0, 164 | ) 165 | ``` 166 | 167 | ## Parameters 168 | 169 | | Parameter | Default | Description | 170 | |-------------------|------------------------|--------------------------------------------------| 171 | | `colors` | `[Colors.purple]` | The gradient colors for the dotted line. | 172 | | `lineThickness` | `2.0` | The thickness of the line. | 173 | | `dashGap` | `5.0` | The space between dashes. | 174 | | `dashWidth` | `5.0` | The width of each dash. | 175 | | `height` | `2.0` | The height of the dotted line. | 176 | | `axis` | `Axis.horizontal` | The direction of the dotted line (horizontal/vertical). | 177 | | `shadowColor` | `Colors.black54` | The color of the shadow. | 178 | | `shadowBlurRadius`| `4.0` | The blur radius of the shadow. | 179 | 180 | ## Example 181 | Here's how you can use `DottedLine` inside a `Column` or `Row` widget: 182 | 183 | ```dart 184 | Column( 185 | children: [ 186 | Text("Above the line"), 187 | DottedLine( 188 | colors: [Colors.red, Colors.orange], 189 | dashWidth: 6.0, 190 | dashGap: 4.0, 191 | ), 192 | Text("Below the line"), 193 | ], 194 | ) 195 | ``` 196 | 197 | This will create a colorful dotted line between two text widgets. 198 | 199 | 200 | 201 | # DottedStar Widget 202 | 203 | ## Overview 204 | `DottedStar` is a customizable Flutter widget that renders a star shape with a dotted outline using a gradient color effect. It is built using `CustomPaint` and provides various customization options. 205 | 206 | ## Features 207 | - Supports gradient colors for the dots. 208 | - Configurable size and number of star points. 209 | - Adjustable dot size and spacing. 210 | - Scalable and rotatable star shape. 211 | 212 | ## Usage 213 | 214 | ### Basic Usage 215 | ```dart 216 | import 'package:flutter/material.dart'; 217 | import 'dotted_star.dart'; 218 | 219 | class MyApp extends StatelessWidget { 220 | @override 221 | Widget build(BuildContext context) { 222 | return MaterialApp( 223 | home: Scaffold( 224 | backgroundColor: Colors.black, 225 | body: Center( 226 | child: DottedStar(), 227 | ), 228 | ), 229 | ); 230 | } 231 | } 232 | ``` 233 | 234 | ### Customization 235 | You can customize the `DottedStar` widget by specifying various parameters. 236 | 237 | ```dart 238 | DottedStar( 239 | gradientColors: [Colors.purple, Colors.pink], 240 | size: 80.0, 241 | points: 6, 242 | dotSize: 4.0, 243 | dotSpacing: 6.0, 244 | scaleFactor: 1.5, 245 | angle: 0.5, // Rotation in radians 246 | ) 247 | ``` 248 | 249 | ## Parameters 250 | 251 | | Parameter | Default Value | Description | 252 | |--------------- |----------------------|--------------------------------------------------| 253 | | `gradientColors` | `[Colors.yellow, Colors.orange]` | List of colors for the gradient effect. | 254 | | `size` | `50.0` | The size of the star. | 255 | | `points` | `5` | Number of points in the star. | 256 | | `dotSize` | `3.0` | The size of each dot in the outline. | 257 | | `dotSpacing` | `5.0` | The spacing between each dot. | 258 | | `scaleFactor` | `1.0` | Scaling factor for resizing the star. | 259 | | `angle` | `0.0` | Rotation angle in radians. | 260 | 261 | ## Implementation Details 262 | 263 | The `DottedStar` widget uses a `CustomPainter` class (`StarPainter`) to draw the dotted outline of a star. It follows these steps: 264 | 1. Creates a star shape using `_createStarPath`. 265 | 2. Applies a radial gradient to the dots. 266 | 3. Iterates over the path using `PathMetrics` to place dots at equal intervals. 267 | 4. Draws each dot on the canvas at calculated positions. 268 | 269 | 270 | # DottedText Widget 271 | 272 | The `DottedText` widget is a custom Flutter widget that renders text using dots instead of solid strokes. It provides customization options for dot size, spacing, colors, and text styling. 273 | 274 | ## Features 275 | - Render text with a dotted effect 276 | - Customizable dot size and spacing 277 | - Supports gradient colors 278 | - Uses Flutter's `CustomPainter` for efficient rendering 279 | 280 | ## Installation 281 | To use `DottedText`, simply add the Dart file to your Flutter project and import it. 282 | 283 | ```dart 284 | import 'package:dotted_line_flutter/dotted_line_flutter.dart'; 285 | ``` 286 | 287 | ## Usage 288 | 289 | ### Basic Usage 290 | ```dart 291 | DottedText( 292 | text: "Hello, World!", 293 | ) 294 | ``` 295 | 296 | ### Customizing Properties 297 | ```dart 298 | DottedText( 299 | text: "Flutter Dots", 300 | textStyle: TextStyle(fontSize: 50, fontWeight: FontWeight.bold, color: Colors.black), 301 | dotSize: 3.0, 302 | dotSpacing: 4.0, 303 | colors: [Colors.red, Colors.orange], 304 | ) 305 | ``` 306 | 307 | ## Parameters 308 | | Parameter | Default Value | Description | 309 | |------------|--------------|-------------| 310 | | `text` | Required | The text to be displayed in dotted style. | 311 | | `textStyle` | `TextStyle(fontSize: 40, fontWeight: FontWeight.bold, color: Colors.black)` | The style of the text. | 312 | | `dotSize` | `2.0` | The size of each individual dot. | 313 | | `dotSpacing` | `3.0` | The spacing between dots. | 314 | | `colors` | `[Colors.purple, Colors.blue]` | A list of colors for gradient effect. | 315 | 316 | 317 | 318 | 319 | # DottedWidget 320 | 321 | DottedWidget is a Flutter custom widget that allows you to create a widget with a customizable dotted border. It supports different shapes, colors, and shadow effects, making it a versatile component for UI design. 322 | 323 | ## Features 324 | - Customizable dotted border 325 | - Supports both rectangular and circular shapes 326 | - Adjustable dash width, gap, and thickness 327 | - Gradient border colors 328 | - Shadow effect for better appearance 329 | 330 | 331 | ## Usage 332 | ```dart 333 | DottedWidget( 334 | width: 150.0, 335 | height: 80.0, 336 | borderRadius: 12.0, 337 | colors: [Colors.blue, Colors.green], 338 | lineThickness: 2.0, 339 | dashWidth: 6.0, 340 | dashGap: 4.0, 341 | shadowBlurRadius: 6.0, 342 | shape: BoxShape.rectangle, 343 | child: const Text("Dotted Box", style: TextStyle(fontSize: 16)), 344 | ), 345 | ``` 346 | 347 | ## Properties 348 | 349 | | Property | Type | Default Value | Description | 350 | |------------------|-------------|---------------|-------------| 351 | | `child` | `Widget?` | `null` | Child widget inside the dotted container. | 352 | | `borderRadius` | `double` | `10.0` | Border radius for rectangle shapes. | 353 | | `colors` | `List` | `[Colors.purple]` | Gradient colors for the border. | 354 | | `lineThickness` | `double` | `2.0` | Thickness of the dotted border. | 355 | | `dashGap` | `double` | `5.0` | Gap between each dot in the border. | 356 | | `dashWidth` | `double` | `5.0` | Width of each individual dot. | 357 | | `axis` | `Axis` | `Axis.horizontal` | Axis along which dots are drawn. | 358 | | `shadowColor` | `Color` | `Colors.black54` | Color of the shadow effect. | 359 | | `shadowBlurRadius` | `double` | `4.0` | Blur radius of the shadow. | 360 | | `width` | `double` | `100.0` | Width of the dotted widget. | 361 | | `height` | `double` | `50.0` | Height of the dotted widget. | 362 | | `shape` | `BoxShape` | `BoxShape.rectangle` | Shape of the dotted widget (rectangle or circle). | 363 | 364 | 365 | 366 | # DottedShape Widget 367 | 368 | A Flutter widget for rendering various shapes with a dotted outline. This can be used to display creative and visually appealing shapes in your app. 369 | 370 | ## Features 371 | - Supports multiple shapes: 372 | - Cone 373 | - Cylinder 374 | - Oval 375 | - Triangle 376 | - Hexagon 377 | - Pentagon 378 | - Hexagram 379 | - Rhombus 380 | - Heart 381 | - Triquetra 382 | - Semicircle 383 | - Crescent 384 | - Fully customizable dot size, spacing, and color. 385 | 386 | 387 | 388 | ## Usage 389 | ```dart 390 | DottedShape( 391 | shapeType: ShapeType.hexagon, 392 | size: 150.0, 393 | dotSize: 5.0, 394 | dotSpacing: 8.0, 395 | dotColor: Colors.blue, 396 | ), 397 | ``` 398 | 399 | ## Customization 400 | | Property | Description | Default Value | 401 | |------------|--------------------------------------------------|--------------| 402 | | `shapeType` | The type of shape to render | `ShapeType.triangle` | 403 | | `size` | The width and height of the shape | `100.0` | 404 | | `dotSize` | The size of each individual dot | `4.0` | 405 | | `dotSpacing` | The spacing between each dot | `6.0` | 406 | | `dotColor` | The color of the dots | `Colors.black` | 407 | 408 | 409 | 410 | 411 | ## Feedback 412 | 413 | If you have any feedback, please reach out to me at puneetsharma5525@gmail.com. 414 | 415 | --- 416 | 417 | ## 👋 Hi, I'm Puneet! 418 | 419 | ### 🚀 About Me 420 | I'm a flutter and spring boot java developer . 421 | 422 | ### 🔗 Links 423 | [![Portfolio](https://img.shields.io/badge/my_portfolio-000?style=for-the-badge&logo=ko-fi&logoColor=white)](https://flutterdartdev.blogspot.com/) 424 | [![LinkedIn](https://img.shields.io/badge/linkedin-0A66C2?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/in/iamapuneet/) 425 | [![Twitter](https://img.shields.io/badge/twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/iamapuneet/) 426 | 427 | 428 | 429 | 430 | ## License 431 | This package is licensed under the MIT License. 432 | 433 | [MIT](https://pub.dev/packages/dotted_line_flutter/license) --------------------------------------------------------------------------------