Loader 011 — Flutter Loader Widget

Free copy-paste Loader 011 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 011 in Flutter

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

Loader 011 – Dart source code

import 'dart:math' as math;
import 'package:flutter/material.dart';

class Loader011 extends StatefulWidget {
  const Loader011({
    super.key,
    this.text = 'LOADING',
    this.textColor = Colors.white,
    this.accentColor = const Color(0xFF888888),
    this.duration = const Duration(milliseconds: 1000),
  });

  final String text;
  final Color textColor;
  final Color accentColor;
  final Duration duration;

  @override
  State<Loader011> createState() => _Loader011State();
}

class _Loader011State extends State<Loader011>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  static const List<double> _fontScales = [
    0.50,
    0.62,
    0.77,
    0.91,
    1.00,
    0.91,
    0.77,
    0.62,
    0.50,
  ];
  static const List<double> _xOffsets = [
    -54.0,
    -26.0,
    -9.0,
    -1.5,
    0.0,
    1.5,
    9.0,
    26.0,
    54.0,
  ];
  static const List<double> _opacities = [
    0.55,
    0.68,
    0.78,
    0.90,
    1.00,
    0.90,
    0.78,
    0.68,
    0.55,
  ];

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

  @override
  void didUpdateWidget(covariant Loader011 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 AnimatedBuilder(
      animation: _controller,
      builder: (context, _) {
        final t = _controller.value;
        final wobble = math.sin(t * 2 * math.pi);

        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            SizedBox(
              width: 140,
              height: 32,
              child: Stack(
                alignment: Alignment.center,
                children: List.generate(9, (i) {
                  final leftBound = i / 9.0;
                  final rightBound = (i + 1) / 9.0;
                  final scale = _fontScales[i];
                  final x = _xOffsets[i];
                  final op = _opacities[i];

                  final scrollT = (t * 2.0 - 1.0);
                  final textShift = scrollT * 60.0;

                  return Positioned(
                    child: Transform.translate(
                      offset: Offset(x, 0),
                      child: Opacity(
                        opacity: op,
                        child: ClipRect(
                          clipper: _SliceClipper(leftBound, rightBound),
                          child: Transform.translate(
                            offset: Offset(textShift, 0),
                            child: Text(
                              widget.text,
                              style: TextStyle(
                                color: widget.textColor,
                                fontSize: 18 * scale,
                                fontWeight: FontWeight.w900,
                                letterSpacing: 2.0,
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  );
                }),
              ),
            ),
            const SizedBox(height: 8),
            Container(
              width: 44,
              height: 3,
              clipBehavior: Clip.antiAlias,
              decoration: BoxDecoration(
                color: widget.textColor.withValues(alpha: 0.25),
                borderRadius: BorderRadius.circular(2),
              ),
              child: FractionallySizedBox(
                alignment: Alignment(wobble, 0.0),
                widthFactor: 0.35,
                child: Container(
                  decoration: BoxDecoration(
                    color: widget.textColor,
                    borderRadius: BorderRadius.circular(2),
                  ),
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}

class _SliceClipper extends CustomClipper<Rect> {
  const _SliceClipper([this.startFrac = 0.0, this.endFrac = 1.0]);

  final double startFrac;
  final double endFrac;

  @override
  Rect getClip(Size size) {
    return Rect.fromLTRB(
      size.width * startFrac,
      0,
      size.width * endFrac,
      size.height,
    );
  }

  @override
  bool shouldReclip(_SliceClipper oldClipper) =>
      oldClipper.startFrac != startFrac || oldClipper.endFrac != endFrac;
}

More Flutter Loaders & Loading Animations