Working with ReorderableListView in Flutter

Last updated on March 7, 2022 Guest Contributor Loading... Post a comment

ReorderableListView is a built-in widget of Flutter which can help us create list views with the items that can be repositioned and reordered by dragging and dropping.

This article will cover the most important things about the ReorderableListView widget and walks you through 2 complete examples of using it in Flutter applications.

What is the point?

1. There are 2 constructors can be used to implement reorderable lists.

Using the ReorderableListView.builder constructor is suitable when your list has a large number of items (usually loaded from APIs or from a database like SQLite). This has three important parameters:

  • itemCount: The number of items in the list
  • itemBuilder: A function to build list item widgets
  • reOrder: A callback function used by the list to report that a list item has been dragged to a new location in the list and the application should update the order of the items.

Using the ReorderableListView constructor is convenient when your list has a small number of items. The main parameters are:

  • children: A list of widgets.
  • reOrder: A callback function used by the list to report that a list item has been dragged to a new location in the list and the application should update the order of the items.

2. In general, ReorderableListView goes with a stateful widget. The reorder functions are almost the same in many cases:

onReorder: (oldIndex, newIndex) {
            setState(() {
              if (newIndex > oldIndex) {
                newIndex = newIndex - 1;
              }
              final item = _myListData.removeAt(oldIndex);
              _myListData.insert(newIndex, element);
            });
}

// Don't forget to change _myListData with your own list 

3. Each item of a ReorderableListView must have a key in order to distinguish the list items after their position is changed. Using ValueKey() is fine. If the keys are missing, a major error will occur.

Examples

ReorderableListView.builder

Preview

This sample app contains a ReorderableListView that holds one hundred fiction products. Each product in this list can be moved to a new location started by a long press gesture then dragging and dropping.

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 const MaterialApp(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

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

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Generate dummy data for the list view
  final List<String> _products =
      List.generate(100, (index) => "Product ${index.toString()}");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Kindacode.com'),
      ),
      body: ReorderableListView.builder(
          itemCount: _products.length,
          itemBuilder: (context, index) {
            final String productName = _products[index];
            return Card(
              key: ValueKey(productName),
              color: Colors.amberAccent,
              elevation: 1,
              margin: const EdgeInsets.all(10),
              child: ListTile(
                contentPadding: const EdgeInsets.all(25),
                title: Text(
                  productName,
                  style: const TextStyle(fontSize: 18),
                ),
                trailing: const Icon(Icons.drag_handle),
                onTap: () {/* Do something else */},
              ),
            );
          },
          // The reorder function
          onReorder: (oldIndex, newIndex) {
            setState(() {
              if (newIndex > oldIndex) {
                newIndex = newIndex - 1;
              }
              final element = _products.removeAt(oldIndex);
              _products.insert(newIndex, element);
            });
          }),
    );
  }
}

ReorderableListView

Preview

This example demonstrates a very common case in real life: a task app allows the user to change the priority of to-do tasks.

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 const MaterialApp(
      // Remove the debug banner
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      // home: HomePage(),
      home: HomePage(),
    );
  }
}

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

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // This variable holds the list's items
  final List<String> _todos = ['Task A', 'Task B', 'Task C', 'Task D'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Kindacode.com'),
      ),
      body: ReorderableListView(
          header: Container(
              padding: const EdgeInsets.all(25),
              color: Colors.amber,
              child: const Text('My Todo List')),
          children: _todos
              .map((task) => Container(
                    key: ValueKey(task),
                    decoration: BoxDecoration(
                        color: Colors.greenAccent,
                        border: Border.all(width: 1, color: Colors.green)),
                    child: ListTile(
                      contentPadding: const EdgeInsets.all(25),
                      leading: const Icon(Icons.lock_clock),
                      title: Text(
                        task,
                        style: const TextStyle(fontSize: 24),
                      ),
                      trailing: const Icon(Icons.drag_handle_outlined),
                    ),
                  ))
              .toList(),
          // The reorder function
          onReorder: (oldIndex, newIndex) {
            setState(() {
              if (newIndex > oldIndex) {
                newIndex -= 1;
              }
              final element = _todos.removeAt(oldIndex);
              _todos.insert(newIndex, element);
            });
          }),
    );
  }
}

Conclusion

We have gone over the fundamentals of the ReorderableListView widget and seen 2 examples of implementing it in practice. If you would like to learn more interesting and new things about Flutter, take a look at the following articles:

You can also check out our Flutter category page or Dart category page for the latest tutorials and examples.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

Related Articles