Kinda Code
Home/Flutter/Working with ListWheelScrollView in Flutter (2 Examples)

Working with ListWheelScrollView in Flutter (2 Examples)

Last updated: September 03, 2023

This article is dedicated to the ListWheelScrollView widget in Flutter. We’ll discover the fundamentals of the widget and then study 2 different examples. The first example is straightforward and nondescript, while the second one is a result of customization – an image carousel/slideshow. Without any further ado, let’s get started.

Overview

The ListWheelScrollView widget, as its name implies, creates a 3D list view with items that seem to be on a fiction wheel whose pivot is a horizontal line behind the screen. Items closer to the middle of the viewport appear larger; conversely, items farther from the center appear smaller.

There is a strict rule we have to adhere to when implementing a ListWheelScrollView widget. That is, all children must be the same size along the scrolling axis (this might be the biggest difference between ListWheeScrollView and ListView). We can set the fixed size with the itemExtend parameter:

// minimal implementation
ListWheelScrollView(
    itemExtend: /* size of each child in main axis (double) */,
    children: /* list items */
)

Now it’s time to see what we can do with it.

The Basic Example

App Preview

The main part of this tiny app is a ListWheelScrollView that presents a list of animals. The selected item will have an orange background color, while other items’ backgrounds are indigo. Moreover, the name of the selected animal will be shown in the Text widget right below the app bar (a little redundant work).

A demo GIF is worth more than a thousand words:

The Code

The complete code with explanations in the comments:

// kindacode.com
// 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(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      title: 'KindaCode.com',
      theme: ThemeData(useMaterial3: true),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // Dummy data to feed the list
  final List _items = [
    'Dog',
    'Cat',
    'Dragon',
    'Crocodile',
    'KindaCode.com',
    'Monkey',
    'Chicken',
    'Flamingo'
  ];

  // The index of the selected item (the one at the middle of the wheel)
  // In the beginning, it's the index of the first item
  int _selectedItemIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('KindaCode.com')),
      body: Column(children: [
        // display selected item
        Container(
            width: double.infinity,
            padding: const EdgeInsets.symmetric(vertical: 50),
            color: Colors.grey.shade800,
            alignment: Alignment.center,
            child: Text(
              _items[_selectedItemIndex],
              style: const TextStyle(fontSize: 32, color: Colors.white),
            )),
        // implement the List Wheel Scroll View
        Expanded(
          child: Container(
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
            width: double.infinity,
            color: Colors.amber.shade200,
            child: ListWheelScrollView(
              itemExtent: 100,
              diameterRatio: 1.8,
              onSelectedItemChanged: (int index) {
                // update the UI on selected item changes
                setState(() {
                  _selectedItemIndex = index;
                });
              },
              // children of the list
              children: _items
                  .map((e) => Card(
                        // make selected item background color is differ from the rest
                        color: _items.indexOf(e) == _selectedItemIndex
                            ? Colors.orange
                            : Colors.indigo,
                        child: Center(
                          child: Text(
                            e,
                            style: const TextStyle(
                                fontSize: 20, color: Colors.white),
                          ),
                        ),
                      ))
                  .toList(),
            ),
          ),
        ),
      ]),
    );
  }
}

Horizontal ListWheelScrollView: Image Carousel/Slideshow

At the time of writing, ListWheelScrollView doesn’t provide any option to make a horizontal list wheel. However, we can achieve the goal without too much effort by using the RotatedBox widget, which rotates its child.

App Preview

This example creates a photo carousel/slideshow. When a photo is selected, its caption will be displayed too. Here’s how it works:

The Code

The full source code with explanations in the comments:

// 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(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      title: 'KindaCode.com',
      theme: ThemeData(useMaterial3: true),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // list of photos to display (including urls and captions)
  final List<Map<String, dynamic>> _photos = [
    {
      "url":
          "https://www.kindacode.com/wp-content/uploads/2022/06/big-boss.jpeg",
      "caption": "Big Boss",
    },
    {
      "url":
          "https://www.kindacode.com/wp-content/uploads/2022/07/flower-1.jpeg",
      "caption": "Flower One"
    },
    {
      "url":
          "https://www.kindacode.com/wp-content/uploads/2022/07/flower-2.jpeg",
      "caption": "Flower Two"
    },
    {
      "url":
          "https://www.kindacode.com/wp-content/uploads/2022/07/flower-3.jpeg",
      "caption": "Flower Three"
    },
    {
      "url":
          "https://www.kindacode.com/wp-content/uploads/2022/07/flower-4.jpeg",
      "caption": "Flower Four"
    }
  ];

  Map<String, dynamic>? _selectedPhoto;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('KindaCode.com')),
      body: Column(
        children: [
          Container(
            height: 400,
            color: Colors.amber,
            alignment: Alignment.center,
            child: RotatedBox(
              quarterTurns: -45,
              // implement the ListWheelScrollView
              child: ListWheelScrollView(
                itemExtent: MediaQuery.of(context).size.width * 0.9,
                onSelectedItemChanged: (index) {
                  setState(() {
                    _selectedPhoto = _photos[index];
                  });
                },
                // use the _photos list as children
                children: _photos
                    .map((photo) => RotatedBox(
                          key: ValueKey(photo["url"]),
                          quarterTurns: 45,
                          child: Image.network(
                            photo["url"],
                            width: double.infinity,
                            height: 300,
                            fit: BoxFit.cover,
                          ),
                        ))
                    .toList(),
              ),
            ),
          ),
          // display the caption of the selected photo
          SizedBox(
            height: 120,
            child: Center(
              child: Text(
                _selectedPhoto == null
                    ? _photos[0]['caption']
                    : _selectedPhoto!['caption'],
                style: const TextStyle(fontSize: 30),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Conclusion

You’ve learned about the ListWheelScrollView widget and examined several examples of using it in practice. Feel free to modify the code, remove some lines, add some lines, and see what happens.

Programming well can be a lifelong endeavor. If you’d like to explore more new and exciting things in modern Flutter, take a look at the following articles:

You can also tour around our Flutter topic page or Dart topic page for the most recent tutorials and examples.