What I need is a reorderable list in iOS styled cupertino Flutter app, very much like the list one gets in iPhone's Reminders app.
To be more specific, say we have the following flutter app:
import 'package:flutter/cupertino.dart';
void main() {
runApp(
CupertinoApp(
title: 'Cupertino App',
theme: const CupertinoThemeData(brightness: Brightness.light),
home: CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
middle: Text('Cupertino List'),
),
child: SafeArea(
child: CupertinoListSection(
header: const Text('Cupertino Items'),
children: [
for (var i = 1; i < 6; i++)
CupertinoListTile(
key: Key('$i'),
title: Text('Item $i'),
),
],
),
),
),
),
);
}
This will create a static list of 5 items named Item 1 through Item 6. I want to be able to long tap on an item and drag it to its new position - much like what material's ReorderableListView accomplishes.
Thanks for making me work on a Cupertino app after a very long time :).
This is the solution I worked on:
class ReorderableListIos extends StatefulWidget {
const ReorderableListIos({super.key});
@override
State<ReorderableListIos> createState() => _ReorderableListIosState();
}
class _ReorderableListIosState extends State<ReorderableListIos> {
final List<int> generatedIntList =
List<int>.generate(10, (int index) => index);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ReorderableListView(
children: [
for (int currentIndex = 0;
currentIndex < generatedIntList.length;
currentIndex += 1)
ListTile(
key: Key('$currentIndex'),
title: Text(' ${generatedIntList[currentIndex]}')),
],
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final int itemToRemove = generatedIntList.removeAt(oldIndex);
generatedIntList.insert(newIndex, itemToRemove);
});
},
),
);
}
}
In case you get an error telling you:
No MaterialLocalizations found.
ReorderableListView widgets require MaterialLocalizations to be provided by a Localizations widget ancestor.
The material library uses Localizations to generate messages, labels, and abbreviations.
To introduce a MaterialLocalizations, either use a MaterialApp at the root of your application to include them automatically, or add a Localization widget with a MaterialLocalizations delegate.
Try adding localizations to your CupertinoApp like so:
localizationsDelegates: [
DefaultMaterialLocalizations.delegate,
DefaultCupertinoLocalizations.delegate,
DefaultWidgetsLocalizations.delegate,
],
Which turns your main function into this:
void main() {
runApp(const CupertinoApp(
home: ReorderableListIos(),
localizationsDelegates: [
DefaultMaterialLocalizations.delegate,
DefaultCupertinoLocalizations.delegate,
DefaultWidgetsLocalizations.delegate,
],
));
}
Hope this helps!
Edit: For some creativity let's change the icon of the drag handle:
First change the ReorderableListView:
ReorderableListView(
buildDefaultDragHandles: false,
...
Then add a trailing ReorderableDragStartListener in order to change the icon:
ListTile(
key: Key('$currentIndex'),
title: Text(' ${generatedIntList[currentIndex]}'),
trailing: ReorderableDragStartListener(
key: ValueKey<int>(generatedIntList[currentIndex]),
index: currentIndex,
child: const Icon(CupertinoIcons.bars),
),
)
Final version:

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With