๐ฏ UI Skeleton Factory
A powerful Flutter package that automatically generates Skeleton Loading UI from any existing Flutter Widget without manually writing skeleton layouts.
โจ Features
- ๐ฏ Automatic Generation: Convert any widget to skeleton with zero configuration
- ๐จ Layout Preservation: Maintains original widget sizes and structure
- โจ Shimmer Animation: Optional smooth shimmer effect for visual feedback
- โก Performance: Optimized for smooth scrolling and minimal overhead
- ๐ง Flexible API: Multiple ways to use (widget, static, extension)
- ๐ญ Smart Mapping: Intelligently maps widgets to appropriate skeleton representations
- ๐ฆ Lightweight: No heavy dependencies, pure Flutter implementation
๐ Quick Start
Installation
Add to your pubspec.yaml:
dependencies:
ui_skeleton_factory: ^0.0.1
Then run:
flutter pub get
Basic Usage
There are three ways to use UI Skeleton Factory:
Method 1: SkeletonFactory Widget
SkeletonFactory(
isLoading: true,
child: ProductCard(product: product),
)
Method 2: Skeleton.from() Static Method
Skeleton.from(
ProductCard(product: fakeProduct),
)
Method 3: Extension API
ProductCard(product: product).skeleton(isLoading: true)
๐ Comprehensive Examples
Example 1: Product Card with Skeleton
import 'package:flutter/material.dart';
import 'package:ui_skeleton_factory/ui_skeleton_factory.dart';
class ProductScreen extends StatefulWidget {
@override
State<ProductScreen> createState() => _ProductScreenState();
}
class _ProductScreenState extends State<ProductScreen> {
bool _isLoading = true;
Product? _product;
@override
void initState() {
super.initState();
_loadProduct();
}
Future<void> _loadProduct() async {
// Simulate API call
await Future.delayed(Duration(seconds: 2));
setState(() {
_product = Product(/* ... */);
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Product Details')),
body: SkeletonFactory(
isLoading: _isLoading,
child: ProductCard(product: _product ?? Product.placeholder()),
),
);
}
}
Example 2: ListView with Skeleton Items
ListView.builder(
itemCount: isLoading ? 10 : items.length,
itemBuilder: (context, index) {
if (isLoading) {
return Skeleton.from(
UserListTile(user: User.placeholder()),
);
}
return UserListTile(user: items[index]);
},
)
Example 3: Using Extension API
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Title').skeleton(isLoading: isLoading),
SizedBox(height: 8),
Text('Subtitle').skeleton(isLoading: isLoading),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
child: Text('Action'),
).skeleton(isLoading: isLoading),
],
)
Example 4: Conditional Skeleton
// Using skeletonIf for cleaner conditional logic
Text('Hello World').skeletonIf(isLoading)
// Equivalent to:
// isLoading ? Skeleton.from(Text('Hello World')) : Text('Hello World')
โ๏ธ Configuration
Custom Colors and Appearance
SkeletonFactory(
isLoading: true,
config: SkeletonConfig(
shimmer: true,
baseColor: Colors.grey[300],
highlightColor: Colors.grey[100],
shimmerDuration: Duration(milliseconds: 1500),
borderRadius: 8.0,
),
child: MyWidget(),
)
Performance Mode (No Shimmer)
For better performance in lists or complex layouts:
// Using predefined performance config
Skeleton.fast(MyWidget())
// Or custom config without shimmer
SkeletonFactory(
isLoading: true,
config: SkeletonConfig(shimmer: false),
child: MyWidget(),
)
Global Configuration
You can use SkeletonConfig.defaultConfig or SkeletonConfig.performanceConfig:
// Default with shimmer
Skeleton.auto(MyWidget())
// Performance mode without shimmer
Skeleton.fast(MyWidget())
๐จ Supported Widgets
UI Skeleton Factory intelligently maps Flutter widgets to skeleton representations:
| Original Widget | Skeleton Representation |
|---|---|
Text |
Rectangular bar with font-based height |
Image / Image.network |
Solid container box |
Icon |
Circle |
CircleAvatar |
Circle matching avatar size |
ElevatedButton / TextButton |
Rounded rectangle |
FloatingActionButton |
Circle |
Card |
Container with rounded corners |
ListTile |
Complete tile layout with leading/title/subtitle |
Checkbox / Radio / Switch |
Small box/circle |
Row / Column |
Preserves layout and spacing |
Stack |
Maintains positioning |
Padding / Center / Align |
Preserves layout constraints |
Expanded / Flexible |
Maintains flex properties |
Layout Preservation
The package automatically preserves:
- โ Widget dimensions (width & height)
- โ Padding and margins
- โ Alignment and positioning
- โ Flex properties (Expanded, Flexible)
- โ Row/Column structure and spacing
- โ Stack positioning
๐ ๏ธ Advanced Usage
Custom Skeleton Widget
If you want complete control, provide a custom skeleton:
SkeletonFactory(
isLoading: true,
skeleton: MyCustomSkeletonWidget(),
child: MyActualWidget(),
)
Using Individual Skeleton Components
import 'package:ui_skeleton_factory/ui_skeleton_factory.dart';
// Skeleton line (for text)
SkeletonLine(
config: SkeletonConfig(),
width: 150,
height: 16,
)
// Skeleton avatar (circular)
SkeletonAvatar(
config: SkeletonConfig(),
size: 40,
)
// Skeleton box (for images)
SkeletonBox(
config: SkeletonConfig(),
aspectRatio: 16 / 9,
)
// Generic skeleton container
SkeletonContainer(
width: 100,
height: 50,
config: SkeletonConfig(),
borderRadius: 8,
isCircular: false,
)
Extension Methods for Specific Widgets
// Text to skeleton line
Text('Title').toSkeletonLine(widthFactor: 0.8)
// Icon to skeleton circle
Icon(Icons.star).toSkeletonCircle()
// Image to skeleton box
Image.network('url').toSkeletonBox(aspectRatio: 16/9)
// CircleAvatar to skeleton avatar
CircleAvatar(radius: 20).toSkeletonAvatar()
๐ Architecture
The package follows a clean, modular architecture:
lib/
โโ core/
โ โโ skeleton_parser.dart // Traverses widget tree
โ โโ widget_mapper.dart // Maps widgets โ skeletons
โ โโ size_resolver.dart // Preserves layout sizes
โ โโ skeleton_context.dart // Configuration
โโ widgets/
โ โโ skeleton_container.dart // Base skeleton components
โ โโ shimmer_effect.dart // Shimmer animation
โ โโ skeleton_wrapper.dart // Loading wrapper logic
โ โโ skeleton_factory.dart // Main widget API
โ โโ skeleton.dart // Static API
โโ extensions/
โโ skeleton_extension.dart // Extension methods
๐ฏ Design Principles
- Zero Configuration: Works out of the box with sensible defaults
- Layout Preservation: Skeletons match original widget dimensions
- Performance First: Optimized for lists and complex layouts
- Flexible API: Multiple usage patterns for different preferences
- Type Safety: Full Dart type safety and null safety support
๐งช Testing
The package includes comprehensive tests covering:
- Widget mapping logic
- Layout preservation
- Configuration handling
- Extension methods
- Edge cases and error handling
Run tests with:
flutter test
๐ฑ Example App
The package includes a full example app demonstrating:
- Basic Demo: Simple widgets with skeleton
- Product Card: Real-world e-commerce card
- ListView Demo: Scrollable list with skeleton items
- Extension API: Using extension methods
- Custom Config: Custom colors and settings
Run the example:
cd example
flutter run
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Show Your Support
If you find this package useful, please give it a โญ๏ธ on GitHub!
๐ฎ Feedback
For bugs, questions, and feature requests, please create an issue on GitHub.
Made with โค๏ธ by Flutter developers, for Flutter developers
Libraries
- core/size_resolver
- core/skeleton_cache
- core/skeleton_context
- core/skeleton_debug
- core/skeleton_parser
- core/skeleton_registry
- core/widget_mapper
- extensions/skeleton_extension
- ui_skeleton_factory
- A Flutter package that automatically generates Skeleton Loading UI from any existing Flutter Widget without manually writing skeleton layouts.
- widgets/shimmer_effect
- widgets/skeleton
- widgets/skeleton_container
- widgets/skeleton_controller
- widgets/skeleton_factory
- widgets/skeleton_switcher
- widgets/skeleton_wrapper