image

26 Dec 2025

9K

35K

Implementing Shimmer Effect Animation on List Items in Flutter

When an application fetches data, especially for lists or feeds, users often experience a brief waiting period. Displaying a static loading indicator can feel unresponsive. A "Shimmer Effect" provides a much more engaging and visually appealing alternative. It's a subtle animation that gives the impression of content being loaded, making the user experience smoother and more pleasant. This article will guide you through implementing a professional Shimmer effect animation on list items in your Flutter application.

Why Use a Shimmer Effect?

The Shimmer effect simulates the layout of the content that is about to appear, typically by displaying a gradient animation over placeholder shapes. This technique offers several benefits:
  • Improved User Experience: It makes the app feel faster and more responsive, as the UI isn't completely static during loading.
  • Visual Engagement: The animation keeps the user engaged rather than staring at a blank screen or a simple spinner.
  • Contextual Loading: Users can anticipate the structure of the incoming content, which is more informative than a generic loader.

Getting Started: Adding the Shimmer Package

For an efficient and ready-to-use Shimmer effect, we'll leverage the popular shimmer package from pub.dev. First, add it to your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  shimmer: ^3.0.0 # Use the latest stable version
After adding the dependency, run flutter pub get in your terminal to fetch the package.

Basic Shimmer Usage

The shimmer package provides a Shimmer.fromColors widget that animates a child widget by overlaying a gradient. You define a baseColor and a highlightColor for the shimmering effect. Here's a simple example applying shimmer to a text widget:

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

class BasicShimmerExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Basic Shimmer')),
      body: Center(
        child: Shimmer.fromColors(
          baseColor: Colors.grey[300]!,
          highlightColor: Colors.grey[100]!,
          child: Text(
            'Loading Text...',
            style: TextStyle(
              fontSize: 28.0,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ),
    );
  }
}

Creating a Shimmer Placeholder Widget for List Items

To apply the shimmer effect effectively to list items, you need to create a placeholder widget that mimics the visual structure of your actual list item. This placeholder will be wrapped by Shimmer.fromColors. Let's create a ShimmerListItemPlaceholder that resembles a typical list item with an avatar and some text lines.

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

class ShimmerListItemPlaceholder extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: 60.0,
            height: 60.0,
            decoration: BoxDecoration(
              color: Colors.white, // Placeholder color for shimmer effect
              shape: BoxShape.circle,
            ),
          ),
          const SizedBox(width: 12.0),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Container(
                  width: double.infinity,
                  height: 16.0,
                  color: Colors.white,
                ),
                const SizedBox(height: 8.0),
                Container(
                  width: MediaQuery.of(context).size.width * 0.7, // Shorter line
                  height: 16.0,
                  color: Colors.white,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
Notice that the color property for the placeholder elements is set to Colors.white. This is because Shimmer.fromColors will paint its gradient over the child's baseColor and highlightColor, making the white child elements appear to shimmer.

Integrating Shimmer into a List View

Now, let's combine the ShimmerListItemPlaceholder with a ListView.builder to display the shimmer effect while data is loading. We'll use a simple Future.delayed to simulate network fetching.

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

// Start of ShimmerListItemPlaceholder definition
class ShimmerListItemPlaceholder extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: 60.0,
            height: 60.0,
            decoration: BoxDecoration(
              color: Colors.white,
              shape: BoxShape.circle,
            ),
          ),
          const SizedBox(width: 12.0),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Container(
                  width: double.infinity,
                  height: 16.0,
                  color: Colors.white,
                ),
                const SizedBox(height: 8.0),
                Container(
                  width: MediaQuery.of(context).size.width * 0.7,
                  height: 16.0,
                  color: Colors.white,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
// End of ShimmerListItemPlaceholder definition

// Start of MyListItem definition
class MyListItem {
  final String title;
  final String subtitle;
  final String imageUrl;

  MyListItem({required this.title, required this.subtitle, required this.imageUrl});
}
// End of MyListItem definition

// Start of ShimmerListScreen definition
class ShimmerListScreen extends StatefulWidget {
  @override
  _ShimmerListScreenState createState() => _ShimmerListScreenState();
}

class _ShimmerListScreenState extends State {
  bool _isLoading = true;
  List _items = [];

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  Future _loadData() async {
    setState(() {
      _isLoading = true;
    });

    // Simulate network delay
    await Future.delayed(Duration(seconds: 3));

    _items = List.generate(
      10,
      (index) => MyListItem(
        title: 'Item Title $index',
        subtitle: 'This is the subtitle for item $index.',
        imageUrl: 'https://via.placeholder.com/150/0000FF/FFFFFF?text=Item+$index', // Example image URL
      ),
    );

    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Shimmer List Example')),
      body: _isLoading
          ? ListView.builder(
              itemCount: 8, // Number of shimmer items to show
              itemBuilder: (context, index) {
                return Shimmer.fromColors(
                  baseColor: Colors.grey[300]!,
                  highlightColor: Colors.grey[100]!,
                  child: ShimmerListItemPlaceholder(),
                );
              },
            )
          : ListView.builder(
              itemCount: _items.length,
              itemBuilder: (context, index) {
                final item = _items[index];
                return Card(
                  margin: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                  child: Padding(
                    padding: const EdgeInsets.all(12.0),
                    child: Row(
                      children: [
                        CircleAvatar(
                          radius: 30,
                          backgroundImage: NetworkImage(item.imageUrl),
                        ),
                        const SizedBox(width: 12.0),
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                item.title,
                                style: TextStyle(
                                  fontSize: 18.0,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                              const SizedBox(height: 4.0),
                              Text(
                                item.subtitle,
                                style: TextStyle(
                                  fontSize: 14.0,
                                  color: Colors.grey[600],
                                ),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
    );
  }
}
// End of ShimmerListScreen definition

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Shimmer Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ShimmerListScreen(),
    );
  }
}
In this example:
  • We define a _isLoading boolean state variable.
  • While _isLoading is true, ListView.builder renders multiple instances of Shimmer.fromColors wrapping ShimmerListItemPlaceholder.
  • Once the simulated data fetching (_loadData) completes, _isLoading becomes false, and the ListView.builder then renders the actual Card widgets with the fetched data.

Customization Options

The Shimmer.fromColors widget offers several properties for customization:
  • baseColor and highlightColor: Control the primary and secondary colors of the gradient.
  • period: Determines the duration of one complete shimmer animation cycle (default is Duration(milliseconds: 1500)).
  • direction: Specifies the direction of the shimmer effect (e.g., ShimmerDirection.ltr for left-to-right, ShimmerDirection.rtl for right-to-left, ShimmerDirection.ttb for top-to-bottom, ShimmerDirection.btt for bottom-to-top).
  • loop: Number of times to loop the animation. Setting it to 0 will make it loop infinitely (default).
  • shimmer: You can also provide a custom Shimmer object for advanced control.

Conclusion

Implementing a Shimmer effect animation in Flutter is an effective way to improve the perceived performance and overall user experience of your application. By using the shimmer package and creating custom placeholder widgets that mirror your actual content structure, you can provide users with an engaging and professional loading indicator for list items and other data-intensive UI components. This technique transforms dull waiting times into a visually rich and informative experience.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is