flutter_animated_skeleton 0.1.0 copy "flutter_animated_skeleton: ^0.1.0" to clipboard
flutter_animated_skeleton: ^0.1.0 copied to clipboard

Impeller-optimized skeleton/shimmer loader with presets and themes.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_animated_skeleton/flutter_animated_skeleton.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Animated Skeleton Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const DemoHomePage(),
    );
  }
}

class DemoHomePage extends StatefulWidget {
  const DemoHomePage({super.key});

  @override
  State<DemoHomePage> createState() => _DemoHomePageState();
}

class _DemoHomePageState extends State<DemoHomePage> {
  bool _showSkeletons = true;
  bool _shimmerEnabled = true;
  bool _isDarkTheme = false;
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return SkeletonTheme(
      data: _isDarkTheme ? SkeletonThemeData.dark() : SkeletonThemeData.light(),
      child: Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: const Text('Flutter Animated Skeleton'),
          actions: [
            IconButton(
              icon: Icon(_isDarkTheme ? Icons.light_mode : Icons.dark_mode),
              onPressed: () {
                setState(() {
                  _isDarkTheme = !_isDarkTheme;
                });
              },
            ),
          ],
        ),
        body: Column(
          children: [
            // Controls
            Container(
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  Row(
                    children: [
                      const Text('Show Skeletons: '),
                      Switch(
                        value: _showSkeletons,
                        onChanged: (value) {
                          setState(() {
                            _showSkeletons = value;
                          });
                        },
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      const Text('Shimmer Effect: '),
                      Switch(
                        value: _shimmerEnabled,
                        onChanged: (value) {
                          setState(() {
                            _shimmerEnabled = value;
                          });
                        },
                      ),
                    ],
                  ),
                ],
              ),
            ),
            const Divider(),
            // Content
            Expanded(child: _buildCurrentScreen()),
          ],
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _currentIndex,
          onTap: (index) {
            setState(() {
              _currentIndex = index;
            });
          },
          items: const [
            BottomNavigationBarItem(icon: Icon(Icons.list), label: 'List'),
            BottomNavigationBarItem(icon: Icon(Icons.grid_view), label: 'Grid'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
          ],
        ),
      ),
    );
  }

  Widget _buildCurrentScreen() {
    switch (_currentIndex) {
      case 0:
        return _showSkeletons
            ? _buildSkeletonListContent()
            : _buildRealListContent();
      case 1:
        return _showSkeletons
            ? _buildSkeletonGridContent()
            : _buildRealGridContent();
      case 2:
        return _showSkeletons
            ? _buildSkeletonProfileContent()
            : _buildRealProfileContent();
      default:
        return _showSkeletons
            ? _buildSkeletonListContent()
            : _buildRealListContent();
    }
  }

  Widget _buildSkeletonListContent() {
    return SkeletonLoader(
      enabled: true,
      shimmer: _shimmerEnabled,
      child: ListView.separated(
        itemCount: 10,
        separatorBuilder: (context, index) => const Divider(height: 1),
        itemBuilder: (context, index) {
          return SkeletonListTile(
            hasLeading: index.isEven,
            titleLines: index % 3 + 1,
            subtitleLines: index.isOdd ? 1 : 0,
            hasTrailing: index % 3 == 0,
          );
        },
      ),
    );
  }

  Widget _buildSkeletonGridContent() {
    return SkeletonLoader(
      enabled: true,
      shimmer: _shimmerEnabled,
      child: SkeletonGrid.count(
        crossAxisCount: 2,
        itemCount: 20,
        mainAxisSpacing: 8,
        crossAxisSpacing: 8,
        itemBuilder: (context, index) {
          return const SkeletonCard(
            hasImage: true,
            titleLines: 2,
            subtitleLines: 1,
            actionCount: 0,
            margin: EdgeInsets.zero,
          );
        },
      ),
    );
  }

  Widget _buildSkeletonProfileContent() {
    return SkeletonLoader(
      enabled: true,
      shimmer: _shimmerEnabled,
      child: SingleChildScrollView(
        child: Column(
          children: [
            const SkeletonProfileHeader(),
            const SizedBox(height: 24),

            // Profile stats section
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: List.generate(
                  3,
                  (index) => Column(
                    children: const [
                      LineSkeleton(width: 40, height: 20),
                      SizedBox(height: 8),
                      LineSkeleton(width: 60, height: 14),
                    ],
                  ),
                ),
              ),
            ),

            const SizedBox(height: 24),

            // Profile content cards
            ...List.generate(
              5,
              (index) => SkeletonCard(
                hasImage: index.isEven,
                titleLines: 1,
                subtitleLines: 2,
                actionCount: 1,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildRealListContent() {
    return ListView.separated(
      itemCount: 10,
      separatorBuilder: (context, index) => const Divider(height: 1),
      itemBuilder: (context, index) {
        return ListTile(
          leading: index.isEven
              ? CircleAvatar(child: Text('${index + 1}'))
              : null,
          title: Text('List Item ${index + 1}'),
          subtitle: index.isOdd ? Text('Subtitle for item ${index + 1}') : null,
          trailing: index % 3 == 0 ? const Icon(Icons.more_vert) : null,
        );
      },
    );
  }

  Widget _buildRealGridContent() {
    return GridView.count(
      crossAxisCount: 2,
      mainAxisSpacing: 8,
      crossAxisSpacing: 8,
      children: List.generate(20, (index) {
        return Card(
          margin: EdgeInsets.zero,
          child: Column(
            children: [
              Expanded(
                child: Container(
                  color: Colors.deepPurple.withValues(alpha: 0.2),
                  child: const Center(child: Icon(Icons.image, size: 48)),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Item ${index + 1}',
                      style: const TextStyle(fontWeight: FontWeight.bold),
                    ),
                    const SizedBox(height: 4),
                    Text('Description for item ${index + 1}'),
                  ],
                ),
              ),
            ],
          ),
        );
      }),
    );
  }

  Widget _buildRealProfileContent() {
    return SingleChildScrollView(
      child: Column(
        children: [
          // Real profile header
          Container(
            padding: const EdgeInsets.all(16),
            child: const Row(
              children: [
                CircleAvatar(
                  radius: 28,
                  backgroundColor: Colors.deepPurple,
                  child: Text(
                    'JD',
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                ),
                SizedBox(width: 16),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'John Doe',
                        style: TextStyle(
                          fontSize: 24,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      SizedBox(height: 4),
                      Text(
                        '@johndoe',
                        style: TextStyle(fontSize: 16, color: Colors.grey),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),

          const SizedBox(height: 16),

          // Profile stats
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: const [
                Column(
                  children: [
                    Text(
                      '1.2K',
                      style: TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    SizedBox(height: 4),
                    Text('Posts', style: TextStyle(color: Colors.grey)),
                  ],
                ),
                Column(
                  children: [
                    Text(
                      '845',
                      style: TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    SizedBox(height: 4),
                    Text('Followers', style: TextStyle(color: Colors.grey)),
                  ],
                ),
                Column(
                  children: [
                    Text(
                      '234',
                      style: TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    SizedBox(height: 4),
                    Text('Following', style: TextStyle(color: Colors.grey)),
                  ],
                ),
              ],
            ),
          ),

          const SizedBox(height: 24),

          // Profile posts
          ...List.generate(
            5,
            (index) => Card(
              margin: const EdgeInsets.all(8),
              child: Column(
                children: [
                  if (index.isEven)
                    Container(
                      height: 200,
                      width: double.infinity,
                      color: Colors.deepPurple.withValues(alpha: 0.2),
                      child: const Center(child: Icon(Icons.image, size: 64)),
                    ),
                  Padding(
                    padding: const EdgeInsets.all(16),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Post ${index + 1}',
                          style: const TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        const SizedBox(height: 8),
                        Text(
                          'This is the content of post ${index + 1}. It contains some interesting information about various topics.',
                        ),
                        const SizedBox(height: 12),
                        const Row(
                          children: [
                            Icon(Icons.favorite_border, size: 20),
                            SizedBox(width: 8),
                            Text('Like'),
                            SizedBox(width: 24),
                            Icon(Icons.comment_outlined, size: 20),
                            SizedBox(width: 8),
                            Text('Comment'),
                          ],
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}
1
likes
160
points
17
downloads

Publisher

verified publisherpixelplatforms.com

Weekly Downloads

Impeller-optimized skeleton/shimmer loader with presets and themes.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, meta

More

Packages that depend on flutter_animated_skeleton