skeleton_tint 0.2.1
skeleton_tint: ^0.2.1 copied to clipboard
Color-matched skeleton loading widgets for Flutter that match the color of the content they replace.
Skeleton Tint #
Tired of skeleton loaders that flash gray then pop into the real colors?
This package keeps it small: color-matched Flutter skeleton widgets that match the color of the content they replace, not just its shape.
Features #
Skeleton— an ambient scope that marks a subtree as loading.SkeletonText— wraps aText; bone color follows the text's own style color. Pass apreviewlistenable to reflow the bone's width as partial text arrives, before the real content is ready.SkeletonImage— drop-in forImage; bone color is sampled from the image's average pixel color, and bone size matches the image's own decoded dimensions whenwidth/heightaren't given.SkeletonBox— wraps aContainer; bone color and size follow the container's owncolor/width/height.SkeletonBone— the low-level shimmer bone used to build custom color-matched placeholders.
width/height are optional everywhere — omit them and each widget sizes
itself from its content (or the space its parent gives it) instead of a
generic placeholder box.
Bone styles #
Every bone animates as a shimmer sweep by default. Set style on the
ambient Skeleton to change it for a whole subtree, or on an individual
SkeletonText/SkeletonImage/SkeletonBox/SkeletonBone to override just
that one:
Skeleton(loading: isLoading, style: SkeletonStyle.pulse, child: const SizedBox());
SkeletonStyle |
Effect |
|---|---|
shimmer |
Gradient highlight sweeping left to right (default). |
wave |
Gradient highlight sweeping top to bottom. |
sheen |
A narrow, brighter band sweeping diagonally. |
pulse |
Opacity fades in and out. |
breathe |
A soft glow that grows and shrinks from the center. |
solid |
A flat, unanimated fill. |
Demo #
Usage #
Add the package to pubspec.yaml
flutter pub add skeleton_tint
or
dependencies:
skeleton_tint: ^0.2.1 # x-release-please-version
Then import the package.
import 'package:skeleton_tint/skeleton_tint.dart';
Wrap a subtree with Skeleton and swap in the color-matched widgets:
Skeleton(
loading: isLoading,
child: Column(
children: [
SkeletonImage(
image: NetworkImage(user.avatarUrl),
borderRadius: BorderRadius.circular(24),
),
SkeletonText(
child: Text(
user.name,
style: const TextStyle(fontSize: 16, color: Colors.black87),
),
),
SkeletonBox(
child: Container(
color: Colors.blue.shade50,
width: 120,
height: 32,
child: PriceTag(product.price),
),
),
],
),
);
Toggle loading on the ambient Skeleton and every descendant
SkeletonText/SkeletonImage/SkeletonBox switches between its bone and
the real widget automatically.
Widget options #
Every property below is optional unless marked required; full docs are on each constructor and on pub.dev.
| Widget | Property | Type | Default | Notes |
|---|---|---|---|---|
Skeleton |
loading |
bool |
required | Whether descendants render their bone instead of real content. |
style |
SkeletonStyle |
shimmer |
Default bone animation style for descendants that don't set their own style. |
|
SkeletonText |
child |
Text |
required | The real Text widget the bone replaces. |
width |
double? |
null |
Max width to wrap lines at. Defaults to the space the parent gives it. | |
preview |
ValueListenable<String?>? |
null |
Partial text known before child's data is final; the bone reflows live as it updates. |
|
borderRadius |
BorderRadius? |
null |
Defaults to a small radius scaled from font size; pass a large radius for a pill shape (e.g. price-tag-like text). | |
style |
SkeletonStyle? |
null |
Overrides the ambient Skeleton.style for this bone. |
|
SkeletonImage |
image |
ImageProvider |
required | The real image; sampled once per instance for its average color. |
width / height |
double? |
null |
Default to the image's own decoded size once known. | |
fit |
BoxFit? |
null |
Forwarded to the real Image once loaded. |
|
borderRadius |
BorderRadius |
BorderRadius.zero |
Applied to both the bone and the real image. | |
style |
SkeletonStyle? |
null |
Overrides the ambient Skeleton.style for this bone. |
|
SkeletonBox |
child |
Container |
required | The real Container the bone replaces. |
color |
Color? |
null |
Defaults to child's own Container.color. |
|
width / height |
double? |
null |
Default to child's own tight size, if any. |
|
borderRadius |
BorderRadius |
BorderRadius.zero |
Bone corner radius. | |
style |
SkeletonStyle? |
null |
Overrides the ambient Skeleton.style for this bone. |
|
SkeletonBone |
color |
Color |
required | The bone's base shimmer color. |
width / height |
double? |
null |
Fill the parent's bounded size, or a fixed extent when unbounded. | |
borderRadius |
BorderRadius |
BorderRadius.circular(4) |
Bone corner radius. | |
style |
SkeletonStyle |
shimmer |
See Bone styles. |
Example App #
The repo includes a runnable example in example/ with
Loading/Loaded tabs to compare the bone and real content side by
side.
cd example
fvm flutter run
Development #
This project uses FVM to pin the Flutter SDK (see
.fvmrc).
fvm flutter pub get
fvm flutter analyze
fvm flutter test
Contributing #
Pull requests are welcome. If you change public behavior or the documented API, keep the README and example app in sync. See CONTRIBUTING.md for details.
Issues #
Bug reports and feature requests are best opened in the GitHub issue tracker.
License #
This project is licensed under the MIT License.
