shimmer_animation_kit 0.1.1
shimmer_animation_kit: ^0.1.1 copied to clipboard
A Flutter package providing shimmer loading animations with auto shape detection, synchronized animation scope, manual widgets, theming, and full accessibility support.
shimmer_animation_kit #
A Flutter package providing shimmer loading animations with auto shape detection, synchronized animation scope, manual widgets, theming, and full accessibility support.
Features #
- Auto shape detection — wrap any widget tree;
ShimmerKitanalyses it and builds a matching skeleton automatically ShimmerScopesync — oneAnimationControllerdrives every shimmer on screen, zero jank- Manual widgets —
ShimmerBox,ShimmerCircleWidget,ShimmerTextWidget,ShimmerListfor hand-crafted layouts - Full theming —
ShimmerTheme(ThemeExtension) with light/dark defaults and per-widget overrides - 5 directions —
leftToRight,rightToLeft,topToBottom,bottomToTop,diagonal - Accessibility — respects
MediaQuery.disableAnimations, exposesSemantics(label: 'Loading') - Zero dependencies — pure Flutter, no third-party packages
Installation #
dependencies:
shimmer_animation_kit: ^0.1.0
Quick Start #
import 'package:shimmer_animation_kit/shimmer_animation_kit.dart';
// 1. Wrap your screen (or subtree) with ShimmerScope.
// 2. Set isLoading: true while fetching data.
ShimmerScope(
child: Column(
children: [
ShimmerKit(
isLoading: _isLoading,
child: ProfileCard(), // real widget shown when loaded
),
ShimmerKit(
isLoading: _isLoading,
child: ArticleList(),
),
],
),
)
Both shimmers share a single animation controller — they pulse in perfect sync.
Auto-Detect vs Manual #
| Use case | Approach |
|---|---|
| Unknown / complex layout | ShimmerKit(isLoading: true, child: ...) |
| Precise hand-crafted layout | ShimmerBox / ShimmerCircleWidget / ShimmerTextWidget |
Auto-detect (ShimmerKit)
ShimmerKit(
isLoading: true,
child: Row(
children: [
CircleAvatar(radius: 24),
Column(children: [Text('Name'), Text('Bio')]),
],
),
)
Manual
ShimmerScope(
child: Row(
children: [
ShimmerCircleWidget(diameter: 48),
const SizedBox(width: 12),
ShimmerTextWidget(lines: 2, width: 140),
],
),
)
API Reference #
| Widget / Class | Key Parameters | Description |
|---|---|---|
ShimmerScope |
duration, child |
Provides shared AnimationController to descendants |
ShimmerKit |
isLoading, child, baseColor, highlightColor, direction |
Auto-detects child shapes and renders shimmer skeleton |
ShimmerBox |
width, height, borderRadius |
Animated rectangle |
ShimmerCircleWidget |
diameter |
Animated circle |
ShimmerTextWidget |
lines, lineHeight, lineSpacing, lastLineWidthFraction, width |
Stacked text-line bars |
ShimmerList |
itemCount, itemBuilder |
Repeating shimmer rows |
ShimmerTheme |
baseColor, highlightColor, duration, direction |
ThemeExtension for app-wide defaults |
ShimmerDirection |
— | Enum: leftToRight, rightToLeft, topToBottom, bottomToTop, diagonal |
ShimmerScope #
ShimmerScope holds one AnimationController and shares its value down the tree via an InheritedWidget. All descendant shimmer widgets read this single value:
ShimmerScope
└─ AnimationController (repeats forever)
└─ _ShimmerScopeInherited (InheritedWidget)
├─ ShimmerBox ← reads value
├─ ShimmerCircleWidget ← reads value
└─ ShimmerKit ← reads value
Why one controller?
Multiple AnimationControllers would drift out of phase. A shared controller guarantees all shimmers are pixel-identical at every frame, with no extra rebuild cost.
Theming #
Register ShimmerTheme in your ThemeData:
ThemeData(
extensions: [
ShimmerTheme(
baseColor: Color(0xFFE0E0E0),
highlightColor: Color(0xFFF5F5F5),
duration: Duration(milliseconds: 1200),
direction: ShimmerDirection.diagonal,
),
],
)
Dark mode — provide a theme extension in your dark ThemeData:
darkTheme: ThemeData.dark().copyWith(
extensions: [ShimmerTheme.dark],
),
If no ShimmerTheme extension is found, the package automatically selects ShimmerTheme.light or ShimmerTheme.dark based on Theme.of(context).brightness.
Accessibility #
When the user enables Reduce Motion on their device, MediaQuery.disableAnimations becomes true. ShimmerScope detects this, stops the controller, and freezes the shimmer at a neutral mid-point value (0.5). The skeleton remains visible but stationary — no flicker, no movement.
Each active shimmer also exposes:
Semantics(label: 'Loading', excludeSemantics: true)
so screen readers announce the loading state without reading phantom widget text.
Contributing #
- Fork the repo and create a feature branch.
- Run
flutter test— all tests must pass. - Run
flutter analyze— zero warnings. - Open a pull request with a clear description.
License #
MIT © 2026 Seqato