flutter_shimmer_effects 1.0.0-dev.1
flutter_shimmer_effects: ^1.0.0-dev.1 copied to clipboard
This package provides various shimmer effects for flutter.
Shimmer Effects #
A modern, highly customizable shimmer effect widget for Flutter. Create beautiful skeleton loading states with ease.
Demo Gallery #
| [Basic shimmer demo] | [Built-in skeletons demo] | [Direction variants demo] |
| [Custom gradient demo] | [List loading demo] |
Features #
- Multiple directions - Left-to-right, right-to-left, top-to-bottom, bottom-to-top
- Smooth bounce mode - Optional ping-pong loop for seamless shimmer
- External control - Synchronize multiple shimmers with
ShimmerController - Accessibility - Respects system "Reduce Motion" settings
- Performance optimized - Built-in
RepaintBoundaryfor efficient rendering in lists - Finite loops - Run animation a specific number of times with completion callback
- Custom gradients - Full control over colors, stops, and blend modes
- Dark mode support -
ShimmerLoadingautomatically adapts to theme brightness - Pre-built skeletons - Ready-to-use skeleton widgets for common UI patterns
Installation #
Add shimmer effects to your pubspec.yaml:
dependencies:
flutter_shimmer_effects: ^1.0.0
Then run:
flutter pub get
Quick Start #
Basic Usage #
import 'package:flutter_shimmer_effects/flutter_shimmer_effects.dart';
Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Container(
width: 200,
height: 100,
color: Colors.white,
),
)
Loading State Management #
Use ShimmerLoading for automatic transitions between loading and content:
ShimmerLoading(
isLoading: _isLoading,
placeholder: SkeletonListTile(),
child: ListTile(
leading: CircleAvatar(backgroundImage: NetworkImage(user.avatar)),
title: Text(user.name),
subtitle: Text(user.email),
),
)
API Reference #
Shimmer #
The core widget that applies an animated gradient mask over its child.
| Property | Type | Default | Description |
|---|---|---|---|
child |
Widget |
required | The widget to apply shimmer effect to |
gradient |
Gradient |
required | The gradient for the shimmer effect |
direction |
ShimmerDirection |
ltr |
Direction of gradient movement |
period |
Duration |
1500ms |
Duration of one animation cycle |
loop |
int |
0 |
Number of loops (0 = infinite) |
bounce |
bool |
false |
Reverse direction each cycle (infinite loop only) |
enabled |
bool |
true |
Whether animation is enabled |
controller |
ShimmerController? |
null |
External controller for sync |
curve |
Curve |
linear |
Animation curve |
blendMode |
BlendMode |
srcIn |
How gradient composites onto child |
respectReducedMotion |
bool |
true |
Honor system accessibility settings |
staticPercent |
double |
0.5 |
Gradient position when motion disabled |
repaintBoundary |
bool |
true |
Wrap in RepaintBoundary for performance |
onAnimationComplete |
VoidCallback? |
null |
Called when finite loops complete |
Shimmer.fromColors
Convenience constructor using two colors:
Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: YourWidget(),
)
ShimmerDirection #
Defines the direction of the shimmer gradient movement:
| Value | Description |
|---|---|
ltr |
Left to right (default) |
rtl |
Right to left |
ttb |
Top to bottom |
btt |
Bottom to top |
ShimmerController #
Manages animation state for one or more Shimmer widgets.
final controller = ShimmerController();
// Control animation
controller.start();
controller.stop();
controller.toggle();
// Check state
controller.isAnimating;
controller.isDisposed;
// Don't forget to dispose
controller.dispose();
Use cases:
- Synchronize multiple shimmer widgets
- Pause animation when content is off-screen
- Programmatically control animation based on app logic
ShimmerLoading #
A convenience widget that manages loading state transitions:
ShimmerLoading(
isLoading: true,
placeholder: SkeletonParagraph(lines: 3),
child: Text('Loaded content'),
fadeTransition: true,
fadeDuration: Duration(milliseconds: 250),
)
| Property | Type | Default | Description |
|---|---|---|---|
isLoading |
bool |
required | Whether to show placeholder |
child |
Widget |
required | Content when loaded |
placeholder |
Widget |
required | Skeleton widget when loading |
baseColor |
Color? |
null |
Override base color |
highlightColor |
Color? |
null |
Override highlight color |
direction |
ShimmerDirection |
ltr |
Direction of gradient movement |
period |
Duration |
1500ms |
Duration of one animation cycle |
bounce |
bool |
false |
Reverse direction each cycle (infinite loop only) |
curve |
Curve |
linear |
Animation curve |
fadeTransition |
bool |
true |
Animate between states |
fadeDuration |
Duration |
250ms |
Transition duration |
respectReducedMotion |
bool |
true |
Honor system accessibility settings |
Skeleton Widgets #
Pre-built skeleton widgets for common UI patterns:
SkeletonLine #
A rectangular skeleton for text lines:
SkeletonLine(
width: double.infinity,
height: 14.0,
borderRadius: BorderRadius.circular(4),
)
SkeletonAvatar #
A circular skeleton for avatars:
SkeletonAvatar(size: 40.0)
SkeletonBox #
A rectangular skeleton for images or cards:
SkeletonBox(
width: 100,
height: 100,
borderRadius: BorderRadius.circular(8),
)
SkeletonListTile #
A composite skeleton mimicking ListTile:
SkeletonListTile(
hasLeading: true,
hasSubtitle: true,
leadingSize: 40.0,
titleWidthFactor: 0.72,
subtitleWidthFactor: 0.52,
)
SkeletonParagraph #
Multiple lines simulating a paragraph:
SkeletonParagraph(
lines: 3,
lineHeight: 14.0,
spacing: 8.0,
lastLineWidthFactor: 0.65,
)
Examples #
List Loading #
ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return ShimmerLoading(
isLoading: _items == null,
placeholder: SkeletonListTile(),
child: _items != null ? ItemTile(item: _items[index]) : SizedBox(),
);
},
)
Card Skeleton #
Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SkeletonBox(width: double.infinity, height: 200),
SizedBox(height: 16),
SkeletonParagraph(lines: 2),
],
),
)
Synchronized Shimmers #
class _MyWidgetState extends State<MyWidget> {
final _controller = ShimmerController();
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Shimmer.fromColors(
controller: _controller,
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: SkeletonLine(),
),
Shimmer.fromColors(
controller: _controller,
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
child: SkeletonLine(),
),
ElevatedButton(
onPressed: _controller.toggle,
child: Text('Toggle'),
),
],
);
}
}
Finite Animation with Callback #
Shimmer.fromColors(
baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!,
loop: 3,
onAnimationComplete: () {
print('Animation completed!');
},
child: Text('Highlight me'),
)
Custom Gradient #
Shimmer(
gradient: LinearGradient(
colors: [Colors.red, Colors.orange, Colors.yellow],
stops: [0.0, 0.5, 1.0],
),
child: Icon(Icons.star, size: 48),
)
Vertical Shimmer #
Shimmer.fromColors(
direction: ShimmerDirection.ttb,
baseColor: Colors.blue[300]!,
highlightColor: Colors.blue[100]!,
child: Container(width: 100, height: 200, color: Colors.white),
)
Performance Tips #
-
RepaintBoundary - Enabled by default. Keep it on when using shimmer in lists.
-
Controller for off-screen content - Stop animation when widgets scroll out of view:
controller.stop(); // When off-screen controller.start(); // When visible again -
Avoid deep nesting - Keep shimmer children relatively simple for best performance.
Accessibility #
By default, Shimmer respects the user's "Reduce Motion" system setting. When reduced motion is enabled:
- Animation stops
- Gradient freezes at
staticPercentposition (default: 0.5)
To override this behavior, set respectReducedMotion: false.
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
License #
MIT License - see the LICENSE file for details.