You can create different types of skeletons using WireFrame widget. Here is the code.
main.dart
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Skeleton Wireframe', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { late final List<User> _users; late final List<Post> _posts; bool _loading = true; Future<void> _loadPosts() async { await Future.delayed(const Duration(seconds: 3)); setState(() { _loading = false; }); } @override void initState() { _users = const [ User( name: 'Dan Brown', photo: 'https://upload.wikimedia.org/wikipedia/commons/5/5f/Alberto_conversi_profile_pic.jpg'), User( name: 'Leanne Graham', photo: 'https://i1.wp.com/www.alphr.com/wp-content/uploads/2020/12/Facebook-How-to-Change-Profile-Picture.jpg?fit=1200%2C666&ssl=1'), User( name: 'Ervin Howell', photo: 'https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500'), ]; _posts = [ Post( date: '22.03.2022', title: 'Lorem ipsum dolor sit amet', text: 'It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters,', user: _users[0]), Post( date: '20.03.2022', title: 'many web sites still in their infancy', text: 'and a search for lorem ipsum will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes', user: _users[1]), Post( date: '17.03.2022', title: 'Lorem Ipsum is not simply random text', text: 'Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur,', user: _users[2]), ]; _loadPosts(); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: SingleChildScrollView( child: Column( children: List.generate(_posts.length, (index) { return Padding( padding: const EdgeInsets.all(16.0), child: _loading ? const PostWireFrame() : PostWidget(post: _posts[index]), ); })), ), ); } } class PostWidget extends StatelessWidget { final Post post; const PostWidget({Key? key, required this.post}) : super(key: key); @override Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ ClipOval( clipBehavior: Clip.hardEdge, child: SizedBox( width: 50, height: 50, child: Image.network( post.user.photo, fit: BoxFit.fill, ), ), ), const SizedBox(width: 15), Text(post.title), ], ), const SizedBox(height: 10), Text(post.text), const SizedBox(height: 10), Align( alignment: Alignment.centerRight, child: Text(post.date), ) ], ), ), ); } } class PostWireFrame extends StatelessWidget { const PostWireFrame({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return SizedBox( height: 200, child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: const [ WireFrame( width: 50, height: 50, shape: BoxShape.circle, ), SizedBox(width: 15), Expanded( child: WireFrame( height: 25, ), ) ], ), const WireFrame( height: 100, ), const Align( alignment: Alignment.centerRight, child: WireFrame( width: 50, height: 25, ), ) ], ), ); } } class WireFrame extends StatefulWidget { final double? width; final double? height; final BoxShape? shape; const WireFrame({Key? key, this.width, this.height, this.shape}) : super(key: key); @override State<WireFrame> createState() => _WireFrameState(); } class _WireFrameState extends State<WireFrame> with SingleTickerProviderStateMixin<WireFrame> { late final AnimationController _controller; late final Animation gradientFirstColorAnim; late final Animation gradientSecondColorAnim; final gradientFirstColorTween = TweenSequence([ TweenSequenceItem( tween: ColorTween(begin: Colors.grey[200], end: Colors.grey[600]), weight: 1), TweenSequenceItem( tween: ColorTween(begin: Colors.grey[600], end: Colors.grey[200]), weight: 1), ]); final gradientSecondColorTween = TweenSequence([ TweenSequenceItem( tween: ColorTween(begin: Colors.grey[600], end: Colors.grey[200]), weight: 1), TweenSequenceItem( tween: ColorTween(begin: Colors.grey[200], end: Colors.grey[600]), weight: 1), ]); @override void dispose() { _controller.dispose(); super.dispose(); } @override void initState() { _controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this); gradientFirstColorAnim = gradientFirstColorTween.animate(_controller); gradientSecondColorAnim = gradientSecondColorTween.animate(_controller); _controller.repeat(); super.initState(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _controller, builder: (context, child) { return Container( width: widget.width, height: widget.height, decoration: BoxDecoration( borderRadius: widget.shape == BoxShape.circle ? null : BorderRadius.circular(5), shape: widget.shape ?? BoxShape.rectangle, gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ gradientFirstColorAnim.value, gradientSecondColorAnim.value, ]), ), ); }); } } class User { final String name; final String photo; const User({required this.name, required this.photo}); } class Post { final User user; final String title; final String text; final String date; const Post( {required this.user, required this.title, required this.text, required this.date}); }
Top comments (0)