Loader 002 — Flutter Loader Widget

Free copy-paste Loader 002 for Flutter: a ready-to-use loader widget with full Dart source code and a live preview. Works on mobile & desktop. No external packages.

  • Category: Loadings
  • Platforms: mobile, desktop
  • Flutter SDK only — no external packages
  • Free to copy & use

How to use Loader 002 in Flutter

Copy the Dart code below into a new file in your Flutter project (for example lib/widgets/loader_002.dart) and use the widget anywhere in your widget tree.

Loader 002 – Dart source code

import 'dart:math' as math;

import 'package:flutter/material.dart';

class Loader002 extends StatefulWidget {
  const Loader002({
    super.key,
    this.size = 36.0,
    this.color = const Color(0xFF69717D),
    this.bladeWidth = 2.8,
    this.bladeLength = 9.0,
    this.duration = const Duration(milliseconds: 1000),
  });

  final double size;
  final Color color;
  final double bladeWidth;
  final double bladeLength;
  final Duration duration;

  @override
  State<Loader002> createState() => _Loader002State();
}

class _Loader002State extends State<Loader002>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

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

  @override
  void didUpdateWidget(covariant Loader002 oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.duration != widget.duration) {
      _controller.duration = widget.duration;
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: widget.size,
      height: widget.size,
      child: AnimatedBuilder(
        animation: _controller,
        builder: (context, _) {
          return CustomPaint(
            painter: _BladePainter(
              progress: _controller.value,
              color: widget.color,
              bladeWidth: widget.bladeWidth,
              bladeLength: widget.bladeLength,
            ),
          );
        },
      ),
    );
  }
}

class _BladePainter extends CustomPainter {
  const _BladePainter({
    this.progress = 0.0,
    this.color = const Color(0xFF69717D),
    this.bladeWidth = 2.8,
    this.bladeLength = 9.0,
  });

  final double progress;
  final Color color;
  final double bladeWidth;
  final double bladeLength;

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.width / 2;

    for (int i = 0; i < 12; i++) {
      final angle = i * (2 * math.pi / 12);
      final delay = i / 12.0;
      final t = (progress - delay) % 1.0;
      final adjustedT = t < 0 ? t + 1.0 : t;
      final alpha = (1.0 - adjustedT).clamp(0.0, 1.0);

      final paint = Paint()
        ..color = color.withValues(alpha: alpha)
        ..strokeWidth = bladeWidth
        ..strokeCap = StrokeCap.round;

      final startDist = radius - bladeLength;
      final p1 = Offset(
        center.dx + startDist * math.cos(angle),
        center.dy + startDist * math.sin(angle),
      );
      final p2 = Offset(
        center.dx + radius * math.cos(angle),
        center.dy + radius * math.sin(angle),
      );

      canvas.drawLine(p1, p2, paint);
    }
  }

  @override
  bool shouldRepaint(_BladePainter oldDelegate) =>
      oldDelegate.progress != progress;
}

More Flutter Loaders & Loading Animations