I'm new to flutter_bloc and trying to implement a ReorderableListView, to allow the user to rerange the order of textfields in a listview.
Unfortunately it isn't working. After dropping the listtile to the new position it changes back to the old one:

This is the output in the screen:
class _Levels extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<DifficultyLevelsCubit, DifficultyLevelsState>(
builder: (context, state) {
print('rebuild');
return Flexible(
child: ReorderableListView(
shrinkWrap: true,
children: state.levels
.asMap()
.map((i, lvl) => MapEntry(
i,
ListTile(
key: ValueKey(i),
title: TextField(
onChanged: (lvl) => context
.read<DifficultyLevelsCubit>()
.levelChanged(lvl, i),
decoration: InputDecoration(
labelText: 'Level',
helperText: '',
errorText: state.levels[i].invalid
? 'invalid level'
: null,
),
),
trailing: Icon(Icons.menu),
),
))
.values
.toList(),
onReorder: (int oldIndex, int newIndex) => context
.read<DifficultyLevelsCubit>()
.orderChanged(oldIndex, newIndex),
),
);
},
);
}
}
And this my implementation of the reorder function in my cubit class:
void orderChanged(int oldIndex, int newIndex) {
List<DiffLevel> _list = state.levels;
if (newIndex > oldIndex) {
newIndex -= 1;
}
final items = _list.removeAt(oldIndex);
_list.insert(newIndex, items);
emit(state.copyWith(levels: _list));
}
Does someone know why this behaviour appears and how to solve this? Thanks in advance!
Note: print('rebuild)` is not being triggerd on reorder. I don't really understand why, cause I emit the state in the reorder function and expect the blocbuilder to react on that change.
What's happening here is you are mutating the same list and not overwriting it - bloc expects and entirely new list in order to rebuild.
Also, I'm not entirely sure you can emit state directly like that. I generally follow the pattern suggested here where the emitted state carries the updated list
const ListState.success(List<Item> items)
: this._(status: ListStatus.success, items: items);
With that said, here 👇🏼 is the approach I would suggest !
void orderChanged(int oldIndex, int newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
// First get the items at the old index
final items = state.levels[oldIndex];
//Then remove it from the old position and insert it at the new one
final reorderedList = List.of(state.levels)
..removeWhere((element) => element.id == items.id)
..insert(newIndex, items);
emit((ListState.success(reorderedList);
}
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