
리스트 아이템을 드래그해서 순서를 변경할 수 있는 Flutter 기본 위젯
Long press → 드래그 → 드롭
별도의 외부 패키지 없이 사용 가능
내부적으로 Drag & Drop + 애니메이션을 처리해줌
ReorderableListView(
onReorder: (oldIndex, newIndex) {},
children: [],
)
| 요소 | 설명 |
|---|---|
onReorder | 아이템 순서 변경 로직 |
children | 반드시 Key가 있는 위젯 목록 |
ReorderableListView는 Key가 없으면 제대로 동작하지 않는다
ListTile(
key: ValueKey(item.id),
title: Text(item.title),
)
Flutter가 위젯을 구분하기 위해 사용
순서 변경 시 어떤 아이템이 이동했는지 알 수 있음
index 기반 Key는 ❌ (버그 원인)
추천 Key
ValueKey(id)
ObjectKey(item)
onReorder: (oldIndex, newIndex) {
if (oldIndex < newIndex) {
newIndex -= 1;
}
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
}
아래로 드래그할 때:
removeAt(oldIndex)로 리스트가 먼저 줄어듦
인덱스가 하나씩 당겨짐
그래서 보정 로직이 필요함
전체 아이템을 길게 누르면 드래그 가능
아이콘으로만 드래그 가능하게 하기
ReorderableListView(
buildDefaultDragHandles: false, // ✨
children: [
ListTile(
key: ValueKey(item.id),
title: Text(item.title),
trailing: ReorderableDragStartListener(
index: index,
child: Icon(Icons.drag_handle),
),
)
],
)
아이템이 많을 경우 builder 사용
ReorderableListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
final item = items[index];
return ListTile(
key: ValueKey(item.id),
title: Text(item.title),
);
},
onReorder: onReorder,
)
child 위젯이 변경될 때 이전 위젯과 새 위젯 사이를 애니메이션으로 전환해주는 위젯
내부적으로 이전 child를 잠시 유지하면서 새 child가 등장하는 애니메이션을 실행
개발자가 직접 AnimationController를 만들 필요 없음
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: 위젯,
)
위젯의 정체성으로 runtimeType + Key 를 사용
= 같은 타입 + 같은 Key → 변경 안 됐다고 판단
타입이 다르거나 Key가 다름 → 전환 애니메이션 실행
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: Text(_count.toString()),
)
→ Text 위젯 타입이 같고 Key가 없어서 변경 감지 못함
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: Text(
_count.toString(),
key: ValueKey(_count),
),
)
✔️ 값이 바뀔 때마다 Key도 바뀜
✔️ AnimatedSwitcher가 변경을 인식
기본 전환 효과는 FadeTransition
아무 설정 안 하면 자동으로 Fade 애니메이션 사용
원하는 애니메이션으로 바꾸려면 transitionBuilder 사용
예: Fade + Scale
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
transitionBuilder: (child, animation) {
return ScaleTransition(
scale: animation,
child: FadeTransition(
opacity: animation,
child: child,
),
);
},
child: Icon(
Icons.favorite,
key: ValueKey(isFavorite),
color: isFavorite ? Colors.red : Colors.grey,
),
);
오늘 강의를 못 들었지만.. 과제를 다시 다듬는 작업을 해봤다