수우주를 개발하던 중 목록의 순서를 드래그해서 바꾸는 기능과 목록을 옆으로 밀어서 삭제하는 기능을 동시에 구현할 필요가 있었다.
그래서 찾아보니 ReorderableListView 와 Dismissible을 동시에 쓰면 될 것 같아서 사용하였다.
Flutter API material library 에 나와있는데로 구현을 해봤다.
ReorderableListView (
padding: const EdgeInsets.symmetric(horizontal: 40),
children: <Widget>[
for (int index = 0; index < _items.length; index += 1)
Dismissible(
key: Key('$index'),
onDismissed: (_) {
setState(() {
_items.removeAt(index);
});
},
child: ListTile(
tileColor: _items[index].isOdd ? oddItemColor : evenItemColor,
title: Text('Item ${_items[index]}'),
),
),
],
onReorder: (int oldIndex, int newIndex) {
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final int item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
);
그런데 목록의 맨마지막 요소를 삭제할 때에는 문제가 없었는데, 목록의 중간 요소를 삭제할 때에 문제가 발생하였다.
A dismissed Dismissible widget is still part of the tree.
Make sure to implement the onDismissed handler and to immediately remove the Dismissible widget from the application once that handler has fired.
대충보니, 삭제한 요소가 아직도 남아 있다는 게 문제인 것 같았다.
스택오버플로우를 검색해 봤더니, 중간요소를 삭제해도 목록에서 중간의 인덱스는 계속 살아남아 있으니, 동일한 키를 가진 위젯이 계속 남아있다고 판단하는 것 같았다.
그래서 거기에서 제시하는 해결책은 UniqueKey()를 key값으로 전달하라는 것이 주로 검색되더라.
그래서 적용해 봤다.
ReorderableListView (
...
children: <Widget>[
for (int index = 0; index < _items.length; index += 1)
Dismissible(
key: UniqueKey(),
...
),
],
...
);
오 그랬더니, 삭제는 잘된다.
그런데, 나는 순서도 바꿀 수 있어야 하는데, 요걸 들어올리니까 목록의 사이로 들어가는 애니메이션이 발생하지 않는다...
아무래도 들어올리는 중에도 위젯을 새로 만들어서 키값이 변경되버리는 결과를 만드는 것 같았다.
결국 내가 해결한 방법은 각 데이터를 가지고 있는 아이템에서 고유 키를 생성해서 주는 방법으로 해결하였다.
ReorderableListView (
...
children: <Widget>[
for (int index = 0; index < _items.length; index += 1)
Dismissible(
key: _items[index].key,
...
),
],
...
);
class Item {
...
Key key = UniqueKey();
...
}
이제 잘 작동한다~!
편리한 나만의 부가세 계산기 찾고 계시다면, 구글플레이에서 수우주를 사용해보세요!