skeletonizer_plus 1.2.0 copy "skeletonizer_plus: ^1.2.0" to clipboard
skeletonizer_plus: ^1.2.0 copied to clipboard

Skeleton loading states for Flutter with shimmer animations, theme-aware colours, automatic tree analysis, and Sliver support.

Skeletonizer Plus #

pub package License: MIT CI

Skeleton loading states for Flutter — shimmer or pulse animations, theme-aware colours, automatic widget-tree analysis, and Sliver support.

Skeletonizer Plus Showcase

Wrap any widget with SkeletonizerPlus and you get a matching skeleton while data loads. Disable it and the original widget is rendered untouched.

Features #

  • Automatic bone generation from common Flutter widgets (Text, Icon, Image, Card, ListTile, CircleAvatar, Container, Row/Column/Padding/Center/Expanded/Flexible/…).
  • Custom bone layouts when you need pixel-precise placeholders — BoneText, BoneRect, BoneCircle, BoneIcon.
  • Shimmer & pulse animations with configurable direction, speed, loops, and colours.
  • Theme-aware — base/highlight colours come from Theme.of(context) automatically.
  • Sliver support via SliverSkeletonizerPlus.
  • SkeletonIgnore to keep specific widgets visible/interactive inside a skeletonised area.
  • SkeletonUnite to collapse a subtree into a single bone.
  • optimizeForPerformance wraps the skeleton in a RepaintBoundary for heavy parent trees.

Install #

dependencies:
  skeletonizer_plus: ^1.2.0
flutter pub get

Quick start #

import 'package:skeletonizer_plus/skeletonizer_plus.dart';

SkeletonizerPlus(
  enabled: isLoading,
  child: ListView.builder(
    itemCount: items.length,
    itemBuilder: (context, i) => Card(
      child: ListTile(
        leading: const CircleAvatar(child: Icon(Icons.person)),
        title: Text(items[i].title),
        subtitle: Text(items[i].subtitle),
      ),
    ),
  ),
)

When isLoading is true, the widget's tree is analysed and replaced with matching skeleton bones. Flip it to false and the real widget takes over.

Custom bone layout #

When automatic generation is too generic, hand-build the skeleton:

SkeletonizerPlus.custom(
  enabled: isLoading,
  bones: const [
    BoneCircle(radius: 30),
    BoneText(words: 4),
    BoneText(words: 6, lines: 2),
    BoneRect(width: 200, height: 100, radius: 12),
    BoneIcon(size: 32),
  ],
  baseColor: Colors.blue.shade200,
  highlightColor: Colors.blue.shade50,
  speed: const Duration(milliseconds: 800),
)

Bone types #

Type What it renders
BoneText One or more lines of word-shaped rectangles. Supports fontSize / style for accurate sizing.
BoneRect A rectangle with an optional corner radius.
BoneCircle A circle. Diameter is radius * 2 or min(width, height).
BoneIcon A square with rounded corners.
BoneWidget Renders a real widget (used internally by SkeletonIgnore).

Animation configuration #

For full control use SkeletonizerPlus.withConfig:

SkeletonizerPlus.withConfig(
  enabled: isLoading,
  animationConfig: const AnimationConfig(
    type: AnimationType.shimmer,        // or AnimationType.pulse
    direction: ShimmerDirection.ltr,    // ltr | rtl | topDown | bottomUp
    speed: Duration(milliseconds: 1200),
    loop: true,
  ),
  child: YourWidget(),
)

Run for a finite number of cycles:

const AnimationConfig(loop: false, loopCount: 3)

Keep widgets visible inside a skeleton #

SkeletonIgnore opts a subtree out of skeletonisation — the wrapped widget renders normally and stays interactive:

SkeletonizerPlus(
  enabled: isLoading,
  child: Row(
    children: [
      const Text('Loading…'),
      SkeletonIgnore(
        child: ElevatedButton(
          onPressed: cancel,
          child: const Text('Cancel'),
        ),
      ),
    ],
  ),
)

Collapse a subtree into one bone #

SkeletonUnite replaces the wrapped widget with a single BoneRect so a row of icons (or any cluster of small widgets) doesn't fragment into noise:

SkeletonUnite(
  child: Row(
    children: const [Icon(Icons.star), Icon(Icons.star), Icon(Icons.star)],
  ),
)

Sliver support #

Use SliverSkeletonizerPlus inside CustomScrollView. The API mirrors SkeletonizerPlus exactly:

CustomScrollView(
  slivers: [
    SliverSkeletonizerPlus(
      enabled: isLoading,
      child: SliverList(
        delegate: SliverChildBuilderDelegate(
          (context, i) => ListTile(title: Text('Item $i')),
          childCount: items.length,
        ),
      ),
    ),
  ],
)

Theming #

Colours default to Colors.grey[300] / Colors.grey[100] in light mode and Colors.grey[800] / Colors.grey[700] in dark mode. Override with baseColor and highlightColor, or supply a full theme: ThemeData(...).

Performance #

  • Set optimizeForPerformance: true to wrap the skeleton in a RepaintBoundary.
  • Animation is driven by a single AnimationController per SkeletonizerPlus, not per bone.
  • Bones are painted as a ShaderMask rather than per-pixel — repaints are cheap.

Platform support #

Platform Filters & transforms
Android Yes
iOS Yes
Web Yes
macOS Yes
Windows Yes
Linux Yes

API reference #

See API_REFERENCE.md.

Author #

Godfrey Lebo — Fullstack Developer & Technical PM

License #

MIT — see LICENSE.

4
likes
160
points
163
downloads

Documentation

API reference

Publisher

verified publishergodfreylebo.dev

Weekly Downloads

Skeleton loading states for Flutter with shimmer animations, theme-aware colours, automatic tree analysis, and Sliver support.

Repository (GitHub)
View/report issues

Topics

#skeleton #loading #shimmer #placeholder #ui

License

MIT (license)

Dependencies

flutter

More

Packages that depend on skeletonizer_plus