Free copy-paste Loader 009 for Flutter: a ready-to-use loader widget with full Dart source code and a live preview. Works on mobile & desktop. No external packages.
Copy the Dart code below into a new file in your Flutter project (for example lib/widgets/loader_009.dart) and use the widget anywhere in your widget tree.
import 'package:flutter/material.dart';
class Loader009 extends StatefulWidget {
const Loader009({
super.key,
this.width = 45.0,
this.height = 40.0,
this.color = Colors.white,
this.blockWidth = 10.0,
this.blockHeight = 14.0,
this.duration = const Duration(milliseconds: 1000),
});
final double width;
final double height;
final Color color;
final double blockWidth;
final double blockHeight;
final Duration duration;
@override
State<Loader009> createState() => _Loader009State();
}
class _Loader009State extends State<Loader009>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: widget.duration)
..repeat();
}
@override
void didUpdateWidget(covariant Loader009 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.width,
height: widget.height,
child: AnimatedBuilder(
animation: _controller,
builder: (context, _) {
return CustomPaint(
painter: _MatrixPainter(
progress: _controller.value,
color: widget.color,
blockWidth: widget.blockWidth,
blockHeight: widget.blockHeight,
),
);
},
),
);
}
}
class _MatrixPainter extends CustomPainter {
const _MatrixPainter({
this.progress = 0.0,
this.color = Colors.white,
this.blockWidth = 10.0,
this.blockHeight = 14.0,
});
final double progress;
final Color color;
final double blockWidth;
final double blockHeight;
@override
void paint(Canvas canvas, Size size) {
canvas.clipRect(Offset.zero & size);
final paint = Paint()
..color = color
..style = PaintingStyle.fill;
final double colGap = (size.width - 3 * blockWidth) / 2;
final double cycleHeight = size.height + blockHeight;
for (int col = 0; col < 3; col++) {
final double x = col * (blockWidth + colGap);
final double offset = col * (1.0 / 3.0);
final double normT = (progress + offset) % 1.0;
final double y1 = size.height - (normT * cycleHeight);
final double y2 = y1 + cycleHeight;
final r1 = RRect.fromRectAndRadius(
Rect.fromLTWH(x, y1, blockWidth, blockHeight),
Radius.circular(blockWidth / 4),
);
canvas.drawRRect(r1, paint);
if (y1 < 0) {
final r2 = RRect.fromRectAndRadius(
Rect.fromLTWH(x, y2, blockWidth, blockHeight),
Radius.circular(blockWidth / 4),
);
canvas.drawRRect(r2, paint);
}
}
}
@override
bool shouldRepaint(_MatrixPainter oldDelegate) =>
oldDelegate.progress != progress;
}