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)