DEV Community

Paul Halliday
Paul Halliday

Posted on • Originally published at developer.school on

Building a Top Ten List: Using ReorderableListView to Reorder List Items

Building a Top Ten List: Using ReorderableListView to Reorder List Items

In this article we'll be looking at how to use ReorderableListView to reorder list items inside of our Flutter applications. The ReorderableListView is part of the Material library and should be used for smaller list(s) without a substantial amount of items.

The ReorderableListView doesn't support the use of a builder method as it uses a SingleChildScrollView under the hood. As a result, you could see performance issue(s) with larger lists - keep this in mind!

Video

Prefer to watch a video? Here's one I recorded for this article:

Project Setup

The project we'll be creating is a simple "Top 10" list where the user can rank a list of items. Here's an example of it in action:

Reorderables!

We'll start by creating a new Flutter project in the terminal:

# New Flutter project
$ flutter create fl_reorderable

# Open in editor
$ cd fl_reorderable && code .

Creating our Top Ten List

Firstly, we'll start off by creating a new Stateful Widget named TopTenList at lib/top_ten_list.dart:

import 'package:flutter/material.dart';

class TopTenList extends StatefulWidget {
  @override
  _TopTenListState createState() => _TopTenListState();
}

class _TopTenListState extends State<TopTenList> {
  List<String> topTenGames = [
    "World of Warcraft",
    "Final Fantasy VII",
    "Animal Crossing",
    "Diablo II",
    "Overwatch",
    "Valorant",
    "Minecraft",
    "Dota 2",
    "Half Life 3",
    "Grand Theft Auto: Vice City"
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Top Ten"),
      ),
      body: ReorderableListView(
        onReorder: (int oldIndex, int newIndex) {},
        children: getListItems(),
      ),
    );
  }

  List<ListTile> getListItems() => topTenGames
      .asMap()
      .map((i, item) => MapEntry(i, buildTenableListTile(item, i)))
      .values
      .toList();

  ListTile buildTenableListTile(String item, int index) {
    return ListTile(
      key: ValueKey(item),
      title: Text(item),
      leading: Text("#${index + 1}"),
    );
  }
}

We've established a List<String> which contains our topTenGames (i.e. the data we'll be using to generate our _reorderableListItems). This'll likely be a more complex model on your end, but a String should suffice for our demo.

Go ahead and add the TopTenList Widget to your main.dart file:

import 'package:fl_reorderable/top_ten_list.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ReorderableListView',
      theme: ThemeData(
        brightness: Brightness.dark,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      debugShowCheckedModeBanner: false,
      home: TopTenList(),
    );
  }
}

Reordering Items

You'll be able to initiate the reorder functionality on our TopTenList by holding down (long press tapping) an item within the list. If you attempt to move this either above or below, it won't work and will snap back to its original position.

This is because we haven't implemented the onReorder function. Let's do exactly that!

Add the onReorder function below and update the ReorderableListView to use this:

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("Top Ten"),
    ),
    body: ReorderableListView(
      onReorder: onReorder,
      children: getListItems(),
    ),
  );
}

void onReorder(int oldIndex, int newIndex) {
  if (newIndex > oldIndex) {
    newIndex -= 1;
  }

  setState(() {
    String game = topTenGames[oldIndex];

    topTenGames.removeAt(oldIndex);
    topTenGames.insert(newIndex, game);
  });
}

This now allows us to directly compare the state of the list depending on whether the user ordered it above or below the current item.

Why does this matter?

Note that if [oldIndex] is before [newIndex], removing the item at [oldIndex] from the list will reduce the list's length by one.

Implementations used by [ReorderableListView] will need to account for this when inserting before [newIndex].

https://chromium.googlesource.com/external/github.com/flutter/flutter/+/v0.8.7/packages/flutter/lib/src/material/reorderable_list.dart

We're then able to remove the item at the oldIndex and replace this with the newIndex, and as we're using setState we're able to trigger a rebuild of the UI. This'll call our getListItems() once more, rendering our new list and surrounding rankings.

Summary

This completes our Top Ten List! We've now got a list that we're able to reorder and display the current ranking. Some possible improvements to this could be:

  1. Give the user an option to create multiple lists with items per list
  2. Allow users to add, remove and edit items in the list
  3. Persist list items to localstorage or shared_preferences

What would you like to see next? I'd love to hear your feedback at https://twitter.com/paulhalliday_io!

Code for this article: https://github.com/PaulHalliday/flutter_top_ten_list

Top comments (0)