[TIL] Day 35 ReorderableListView & AnimatedSwitcher

현서·2026년 1월 13일

[TIL] Flutter 9기

목록 보기
47/65
post-thumbnail

📍 튜터님과 Widget 공부

✏️ ReorderableListView

ReorderableListView란?

리스트 아이템을 드래그해서 순서를 변경할 수 있는 Flutter 기본 위젯
Long press → 드래그 → 드롭
별도의 외부 패키지 없이 사용 가능
내부적으로 Drag & Drop + 애니메이션을 처리해줌

기본 구조

ReorderableListView(
  onReorder: (oldIndex, newIndex) {},
  children: [],
)
요소설명
onReorder아이템 순서 변경 로직
children반드시 Key가 있는 위젯 목록

가장 중요한 포인트: Key

ReorderableListView는 Key가 없으면 제대로 동작하지 않는다

ListTile(
  key: ValueKey(item.id),
  title: Text(item.title),
)

왜 Key가 필요할까?

Flutter가 위젯을 구분하기 위해 사용
순서 변경 시 어떤 아이템이 이동했는지 알 수 있음
index 기반 Key는 ❌ (버그 원인)

추천 Key
ValueKey(id)
ObjectKey(item)

onReorder 동작 원리

onReorder: (oldIndex, newIndex) {
  if (oldIndex < newIndex) {
    newIndex -= 1;
  }

  final item = items.removeAt(oldIndex);
  items.insert(newIndex, item);
}

왜 newIndex -= 1 이 필요할까?

아래로 드래그할 때:
removeAt(oldIndex)로 리스트가 먼저 줄어듦
인덱스가 하나씩 당겨짐
그래서 보정 로직이 필요함

드래그 핸들 커스터마이징

전체 아이템을 길게 누르면 드래그 가능
아이콘으로만 드래그 가능하게 하기

ReorderableListView(
  buildDefaultDragHandles: false, // ✨
  children: [
    ListTile(
      key: ValueKey(item.id),
      title: Text(item.title),
      trailing: ReorderableDragStartListener(
        index: index,
        child: Icon(Icons.drag_handle),
      ),
    )
  ],
)

ReorderableListView.builder

아이템이 많을 경우 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,
)

✏️ AnimatedSwitcher

AnimatedSwitcher란?

child 위젯이 변경될 때 이전 위젯과 새 위젯 사이를 애니메이션으로 전환해주는 위젯
내부적으로 이전 child를 잠시 유지하면서 새 child가 등장하는 애니메이션을 실행
개발자가 직접 AnimationController를 만들 필요 없음

기본 구조

AnimatedSwitcher(
  duration: Duration(milliseconds: 300),
  child: 위젯,
)
  • child가 바뀌면 애니메이션 발생
  • 바뀌지 않으면 아무 일도 안 일어남

동작 원리

위젯의 정체성으로 runtimeType + Key 를 사용
= 같은 타입 + 같은 Key → 변경 안 됐다고 판단
타입이 다르거나 Key가 다름 → 전환 애니메이션 실행

가장 중요한 포인트: Key

  • 애니메이션이 안 되는 경우
AnimatedSwitcher(
  duration: Duration(milliseconds: 300),
  child: Text(_count.toString()),
)

→ Text 위젯 타입이 같고 Key가 없어서 변경 감지 못함

  • 올바른 예 (Key 사용)
AnimatedSwitcher(
  duration: Duration(milliseconds: 300),
  child: Text(
    _count.toString(),
    key: ValueKey(_count),
  ),
)

✔️ 값이 바뀔 때마다 Key도 바뀜
✔️ AnimatedSwitcher가 변경을 인식

transitionBuilder (커스텀 애니메이션)

기본 전환 효과는 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,
  ),
);

공부 소감

오늘 강의를 못 들었지만.. 과제를 다시 다듬는 작업을 해봤다

0개의 댓글