dashed_painter 1.1.0 copy "dashed_painter: ^1.1.0" to clipboard
dashed_painter: ^1.1.0 copied to clipboard

A simple Flutter plugin to draw dashed lines and shapes on canvas easily.

example/lib/main.dart

import 'package:dashed_painter/dashed_painter.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    /// start benchmark
    //return const MaterialApp(home: BenchmarkScreen());
    /// end benchmark

    /// start demo
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Dash Painter Demo v1.1.0',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const DemoHome(),
    );
  }
}

class DemoHome extends StatefulWidget {
  const DemoHome({super.key});

  @override
  State<DemoHome> createState() => _DemoHomeState();
}

class _DemoHomeState extends State<DemoHome> {
  int _selectedIndex = 0;

  final List<Widget> _screens = [
    const BasicDemoScreen(),
    const AnimationDemoScreen(),
    const PatternDemoScreen(),
    const PerformanceDemoScreen(),
  ];

  final List<String> _titles = [
    'Basic Shapes',
    'Animation Demo',
    'Custom Patterns',
    'Performance',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_titles[_selectedIndex]),
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
      ),
      body: _screens[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _selectedIndex,
        onTap: (index) => setState(() => _selectedIndex = index),
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.share), label: 'Basic'),
          BottomNavigationBarItem(
            icon: Icon(Icons.animation),
            label: 'Animation',
          ),
          BottomNavigationBarItem(icon: Icon(Icons.pattern), label: 'Patterns'),
          BottomNavigationBarItem(
            icon: Icon(Icons.speed),
            label: 'Performance',
          ),
        ],
      ),
    );
  }
}

// 🎨 Basic Demo Screen - Traditional dashed shapes
class BasicDemoScreen extends StatelessWidget {
  const BasicDemoScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: CustomPaint(
        size: const Size(400, 400),
        painter: DashedGeometryPainter(),
      ),
    );
  }
}

// ✨ Animation Demo Screen - Marching ants effects
class AnimationDemoScreen extends StatefulWidget {
  const AnimationDemoScreen({super.key});

  @override
  State<AnimationDemoScreen> createState() => _AnimationDemoScreenState();
}

class _AnimationDemoScreenState extends State<AnimationDemoScreen>
    with TickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const Padding(
          padding: EdgeInsets.all(16.0),
          child: Text(
            '🐜 Marching Ants Effect',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
        ),
        Expanded(
          child: Center(
            child: AnimatedBuilder(
              animation: _controller,
              builder: (context, child) {
                return CustomPaint(
                  size: const Size(350, 350),
                  painter: AnimatedDashPainter(_controller.value * 20),
                );
              },
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.all(16.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ElevatedButton(
                onPressed: () => _controller.repeat(),
                child: const Text('Start'),
              ),
              ElevatedButton(
                onPressed: () => _controller.stop(),
                child: const Text('Stop'),
              ),
              ElevatedButton(
                onPressed: () => _controller.reset(),
                child: const Text('Reset'),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

// 🎭 Pattern Demo Screen - Custom dash patterns
class PatternDemoScreen extends StatelessWidget {
  const PatternDemoScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const Padding(
          padding: EdgeInsets.all(16.0),
          child: Text(
            '🎨 Custom Dash Patterns',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
        ),
        Expanded(
          child: ListView(
            padding: const EdgeInsets.all(16.0),
            children: [
              _buildPatternCard('Morse Code', [8, 4, 2, 4, 8, 4, 2, 4]),
              _buildPatternCard('Railroad', [12, 6, 3, 6]),
              _buildPatternCard('Heartbeat', [20, 3, 5, 3, 5, 15]),
              _buildPatternCard('Stairs', [2, 2, 4, 2, 6, 2, 8, 2]),
              _buildPatternCard('Musical', [10, 5, 3, 5, 3, 5, 10, 15]),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildPatternCard(String name, List<double> pattern) {
    return Card(
      margin: const EdgeInsets.only(bottom: 16.0),
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              name,
              style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            Text(
              'Pattern: [${pattern.join(', ')}]',
              style: const TextStyle(
                fontSize: 12,
                color: Colors.grey,
                fontFamily: 'monospace',
              ),
            ),
            const SizedBox(height: 16),
            CustomPaint(
              size: const Size(double.infinity, 40),
              painter: PatternDemoPainter(pattern),
            ),
          ],
        ),
      ),
    );
  }
}

// ⚡ Performance Demo Screen - Caching demonstration
class PerformanceDemoScreen extends StatefulWidget {
  const PerformanceDemoScreen({super.key});

  @override
  State<PerformanceDemoScreen> createState() => _PerformanceDemoScreenState();
}

class _PerformanceDemoScreenState extends State<PerformanceDemoScreen> {
  bool _enableCaching = true;
  int _shapeCount = 50;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        const Padding(
          padding: EdgeInsets.all(16.0),
          child: Text(
            '⚡ Performance Optimization',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
        ),
        Card(
          margin: const EdgeInsets.all(16.0),
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    const Text('Enable Caching:'),
                    Switch(
                      value: _enableCaching,
                      onChanged: (value) {
                        setState(() {
                          _enableCaching = value;
                          if (!value) DashedPainter.clearCache();
                        });
                      },
                    ),
                  ],
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [const Text('Shape Count:'), Text('$_shapeCount')],
                ),
                Slider(
                  value: _shapeCount.toDouble(),
                  min: 10,
                  max: 200,
                  divisions: 19,
                  onChanged: (value) {
                    setState(() {
                      _shapeCount = value.round();
                    });
                  },
                ),
                Text('Cache Size: ${DashedPainter.cacheSize}'),
                ElevatedButton(
                  onPressed: () {
                    DashedPainter.clearCache();
                    setState(() {});
                  },
                  child: const Text('Clear Cache'),
                ),
              ],
            ),
          ),
        ),
        Expanded(
          child: CustomPaint(
            size: Size.infinite,
            painter: PerformanceDemoPainter(_shapeCount, _enableCaching),
          ),
        ),
      ],
    );
  }
}

// 🧱 Original Painters (kept for compatibility)

class DashedGeometryPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);

    Paint paint =
        Paint()
          ..style = PaintingStyle.stroke
          ..color = Colors.blue
          ..strokeWidth = 1;

    final Path path = Path();
    path.moveTo(-200, 0);
    path.lineTo(200, 0);
    path.moveTo(0, -200);
    path.lineTo(0, 200);

    path.addOval(Rect.fromCircle(center: Offset.zero, radius: 80));
    path.addRRect(
      RRect.fromRectAndRadius(
        Rect.fromCircle(center: Offset.zero, radius: 100),
        Radius.circular(20),
      ),
    );
    const DashedPainter(span: 4, step: 9).paint(canvas, path, paint);
  }

  @override
  bool shouldRepaint(covariant DashedGeometryPainter oldDelegate) => false;
}

// 🎬 New v1.1.0 Painters

class AnimatedDashPainter extends CustomPainter {
  final double animationOffset;

  AnimatedDashPainter(this.animationOffset);

  @override
  void paint(Canvas canvas, Size size) {
    canvas.translate(size.width / 2, size.height / 2);

    final paint =
        Paint()
          ..style = PaintingStyle.stroke
          ..color = Colors.purple
          ..strokeWidth = 3;

    // Animated circle
    final circlePath =
        Path()..addOval(Rect.fromCircle(center: Offset.zero, radius: 80));
    DashedPainter(
      step: 8,
      span: 4,
      animationOffset: animationOffset,
    ).paint(canvas, circlePath, paint);

    // Animated square
    paint.color = Colors.green;
    final squarePath =
        Path()..addRect(
          Rect.fromCenter(center: Offset.zero, width: 120, height: 120),
        );
    DashedPainter(
      step: 6,
      span: 3,
      animationOffset: -animationOffset * 1.5, // Reverse direction
    ).paint(canvas, squarePath, paint);

    // Animated heart shape
    paint.color = Colors.red;
    final heartPath = _createHeartPath();
    DashedPainter.pattern(
      dashPattern: [10, 5, 3, 5],
      animationOffset: animationOffset * 0.8,
    ).paint(canvas, heartPath, paint);
  }

  Path _createHeartPath() {
    final path = Path();
    path.moveTo(0, 20);
    path.cubicTo(-40, -20, -80, 10, 0, 60);
    path.cubicTo(80, 10, 40, -20, 0, 20);
    return path;
  }

  @override
  bool shouldRepaint(AnimatedDashPainter oldDelegate) {
    return oldDelegate.animationOffset != animationOffset;
  }
}

class PatternDemoPainter extends CustomPainter {
  final List<double> pattern;

  PatternDemoPainter(this.pattern);

  @override
  void paint(Canvas canvas, Size size) {
    final paint =
        Paint()
          ..style = PaintingStyle.stroke
          ..color = Colors.blue
          ..strokeWidth = 3;

    final path =
        Path()
          ..moveTo(20, size.height / 2)
          ..lineTo(size.width - 20, size.height / 2);

    DashedPainter.pattern(dashPattern: pattern).paint(canvas, path, paint);
  }

  @override
  bool shouldRepaint(PatternDemoPainter oldDelegate) {
    return oldDelegate.pattern != pattern;
  }
}

class PerformanceDemoPainter extends CustomPainter {
  final int shapeCount;
  final bool enableCaching;

  PerformanceDemoPainter(this.shapeCount, this.enableCaching);

  @override
  void paint(Canvas canvas, Size size) {
    final paint =
        Paint()
          ..style = PaintingStyle.stroke
          ..strokeWidth = 1;

    for (int i = 0; i < shapeCount; i++) {
      final double x = (i % 10) * (size.width / 10) + 20;
      final double y = (i ~/ 10) * 40 + 40;
      final double radius = 15 + (i % 3) * 5;

      paint.color = Colors.primaries[i % Colors.primaries.length];

      final path =
          Path()
            ..addOval(Rect.fromCircle(center: Offset(x, y), radius: radius));

      DashedPainter(
        step: 4,
        span: 2,
        enableCaching: enableCaching,
      ).paint(canvas, path, paint);
    }
  }

  @override
  bool shouldRepaint(PerformanceDemoPainter oldDelegate) {
    return oldDelegate.shapeCount != shapeCount ||
        oldDelegate.enableCaching != enableCaching;
  }
}
2
likes
130
points
21
downloads

Publisher

unverified uploader

Weekly Downloads

A simple Flutter plugin to draw dashed lines and shapes on canvas easily.

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on dashed_painter

Packages that implement dashed_painter