image

20 Jan 2026

9K

35K

Creating a Multi-Item Image Carousel Widget in Flutter

Image carousels are a common UI pattern used to display multiple images or cards in a compact, scrollable format. They are highly effective for showcasing products, highlighting features, or presenting a gallery of images in a visually engaging way. In Flutter, creating such a widget is straightforward, especially when leveraging community packages.

This article will guide you through the process of building a dynamic, multi-item image carousel using the popular carousel_slider package. This package simplifies the implementation of complex carousel behaviors, including auto-play, infinite scroll, and custom item layouts.

Prerequisites

  • Basic understanding of Flutter development.
  • A Flutter development environment set up.

Step 1: Add the Dependency

First, you need to add the carousel_slider package to your Flutter project. Open your pubspec.yaml file and add the dependency under dependencies:


dependencies:
  flutter:
    sdk: flutter
  carousel_slider: ^4.2.1 # Use the latest version

After adding, run flutter pub get in your terminal to fetch the new package.

Step 2: Prepare Your Data

For this example, we'll use a simple list of image URLs. In a real-world application, this data might come from an API or a local asset folder.


final List imgList = [
  'https://images.unsplash.com/photo-1520342868574-5fa3804e551c?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=6ff92caf5590b05be217c60c708cdb6fa&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1522205408450-fdc7d036c87f?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=7dce60ae46422ce4435809756b1bc32e&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1519985176271-adfd5a3b999b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=2a8e3d08dd8a3e742e1cc7186106e232&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1523205771715-94f38ca-a20d?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=3f8974a40d5859d2822a10f9b699a221&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1508704019882-f9cf1416e1c1?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=86c0c2a5c43d22b005e834882143497d&auto=format&fit=crop&w=1950&q=80',
  'https://images.unsplash.com/photo-1519985176271-adfd5a3b999b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=2a8e3d08dd8a3e742e1cc7186106e232&auto=format&fit=crop&w=1950&q=80'
];

Step 3: Create the Carousel Widget

We'll create a StatefulWidget to manage the current page index for the indicators. The core of our carousel will be the CarouselSlider.builder.


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

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

  @override
  State createState() => _MultiItemImageCarouselState();
}

class _MultiItemImageCarouselState extends State {
  int _current = 0;
  final CarouselController _controller = CarouselController();

  final List imgList = [
    'https://images.unsplash.com/photo-1520342868574-5fa3804e551c?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=6ff92caf5590b05be217c60c708cdb6fa&auto=format&fit=crop&w=1950&q=80',
    'https://images.unsplash.com/photo-1522205408450-fdc7d036c87f?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=7dce60ae46422ce4435809756b1bc32e&auto=format&fit=crop&w=1950&q=80',
    'https://images.unsplash.com/photo-1519985176271-adfd5a3b999b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=2a8e3d08dd8a3e742e1cc7186106e232&auto=format&fit=crop&w=1950&q=80',
    'https://images.unsplash.com/photo-1523205771715-94f38ca-a20d?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=3f8974a40d5859d2822a10f9b699a221&auto=format&fit=crop&w=1950&q=80',
    'https://images.unsplash.com/photo-1508704019882-f9cf1416e1c1?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=86c0c2a5c43d22b005e834882143497d&auto=format&fit=crop&w=1950&q=80',
    'https://images.unsplash.com/photo-1519985176271-adfd5a3b999b?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=2a8e3d08dd8a3e742e1cc7186106e232&auto=format&fit=crop&w=1950&q=80'
  ];

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        CarouselSlider.builder(
          itemCount: imgList.length,
          carouselController: _controller,
          itemBuilder: (BuildContext context, int index, int realIndex) {
            return Builder(
              builder: (BuildContext context) {
                return Container(
                  width: MediaQuery.of(context).size.width,
                  margin: const EdgeInsets.symmetric(horizontal: 5.0),
                  decoration: BoxDecoration(
                    color: Colors.grey,
                    borderRadius: BorderRadius.circular(8.0),
                  ),
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(8.0),
                    child: Image.network(
                      imgList[index],
                      fit: BoxFit.cover,
                      errorBuilder: (context, error, stackTrace) => const Center(
                        child: Icon(Icons.broken_image, size: 50, color: Colors.white),
                      ),
                    ),
                  ),
                );
              },
            );
          },
          options: CarouselOptions(
            height: 200.0,
            autoPlay: true,
            enlargeCenterPage: true,
            aspectRatio: 16 / 9,
            autoPlayCurve: Curves.fastOutSlowIn,
            enableInfiniteScroll: true,
            autoPlayAnimationDuration: const Duration(milliseconds: 800),
            viewportFraction: 0.8, // This is key for showing multiple items
            onPageChanged: (index, reason) {
              setState(() {
                _current = index;
              });
            },
          ),
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: imgList.asMap().entries.map((entry) {
            return GestureDetector(
              onTap: () => _controller.animateToPage(entry.key),
              child: Container(
                width: 12.0,
                height: 12.0,
                margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: (Theme.of(context).brightness == Brightness.dark
                          ? Colors.white
                          : Colors.black)
                      .withOpacity(_current == entry.key ? 0.9 : 0.4),
                ),
              ),
            );
          }).toList(),
        ),
      ],
    );
  }
}

Explanation of Key Options:

  • itemCount: The total number of items in the carousel.
  • carouselController: An optional controller to programmatically control the carousel (e.g., jump to a specific page).
  • itemBuilder: A function that builds each item in the carousel. Here, we display an Image.network wrapped in a Container with rounded corners.
  • height: Defines the height of the carousel.
  • autoPlay: If set to true, the carousel will automatically advance.
  • enlargeCenterPage: Makes the current item larger than others, giving it more prominence.
  • viewportFraction: This is crucial for a "multi-item" display. A value less than 1.0 (e.g., 0.8) means that only 80% of the viewport width is taken by the current item, allowing parts of the previous and next items to be visible.
  • onPageChanged: A callback that fires when the page changes, allowing us to update the _current index for the indicators.

Step 4: Adding Page Indicators

To enhance user experience, we'll add a row of dots below the carousel to indicate the current active page. These dots will also be tappable to navigate directly to a page.

Inside the Column, after the CarouselSlider, add the following code:


        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: imgList.asMap().entries.map((entry) {
            return GestureDetector(
              onTap: () => _controller.animateToPage(entry.key),
              child: Container(
                width: 12.0,
                height: 12.0,
                margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: (Theme.of(context).brightness == Brightness.dark
                          ? Colors.white
                          : Colors.black)
                      .withOpacity(_current == entry.key ? 0.9 : 0.4),
                ),
              ),
            );
          }).toList(),
        ),

This code iterates through the image list, creating a circular Container for each image. The color of the dot changes based on whether its index matches the _current active page. Tapping a dot uses the CarouselController to animate to the corresponding page.

Step 5: Integrate into Your App

Finally, you can integrate your MultiItemImageCarousel widget into your main.dart or any other screen in your application:


import 'package:flutter/material.dart';
import 'package:your_app_name/multi_item_image_carousel.dart'; // Adjust import path

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Carousel Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Multi-Item Image Carousel'),
        ),
        body: const Center(
          child: MultiItemImageCarousel(),
        ),
      ),
    );
  }
}

Conclusion

You have successfully created a multi-item image carousel in Flutter. The carousel_slider package provides a robust and flexible solution for implementing various carousel designs with minimal code. By adjusting options like viewportFraction, enlargeCenterPage, and customizing the itemBuilder, you can tailor the carousel to perfectly fit your application's aesthetic and functional requirements.

Experiment with different settings and styling to create truly unique and engaging user interfaces.

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