Dismissible class
표시된 방향으로 드래그하여 닫을 수 있는 위젯입니다.
DismissDirection 에서 이 위젯을 드래그하거나 던지면 자식 위젯이 슬라이드 아웃됩니다. 슬라이드 애니메이션 후 resizeDuration 이 null이 아니면 Dismissible 위젯은 resizeDuration 에 지정된 시간 동안 높이(또는 해제 방향과 수직인 너비)를 0으로 애니메이션 합니다.
공식 문서 코드
Dismissible 위젯은 리스트나 아이템등 카드처럼 표시된 위젯을 스와이프로 지울 수 있도록 도와주는 위젯인데 보통 위의 예제처럼 주로 ListView.builder 같은 코드와 함께 사용된다. 주요 기능으로는 스와이프 방향설정(가로, 세로)과 삭제 확인, 콜백을 제공해 주는다는 점을 꼽을 수 있겠다. 한번 알아보자.
하위 속성
속성명 | 타입 | 기본값 | 설명 |
child | Widget | – | 실제로 화면에 보여질 자식 위젯 |
background | Widget? | null | 주로 오른쪽 또는 아래로 드래그할 때 뒤에 보여지는 배경 위젯 |
secondaryBackground | Widget? | null | 왼쪽 또는 위로 드래그할 때 뒤에 보여지는 배경 위젯 |
confirmDismiss | ConfirmDismissCallback? | null | 삭제 전 확인을 위한 콜백 함수 (true 반환 시 삭제) |
onResize | VoidCallback? | null | 위젯이 축소(resize)될 때 호출되는 콜백 |
onDismissed | DismissDirectionCallback? | null | 완전히 삭제된 후 호출되는 콜백 함수 |
direction | DismissDirection | DismissDirection.horizontal | 스와이프 가능한 방향 설정 (horizontal, vertical 등) |
resizeDuration | Duration? | 300ms | 삭제 시 위젯이 축소되는 애니메이션 시간 |
dismissThresholds | Map<DismissDirection, double> | {} | 삭제로 판단되는 드래그 거리 비율 (0.0~1.0) |
movementDuration | Duration | 200ms | 위젯 이동 애니메이션 시간 |
crossAxisEndOffset | double | 0.0 | 삭제된 후 위젯이 이동할 보조 축 방향 거리 |
dragStartBehavior | DragStartBehavior | DragStartBehavior.start | 드래그 시작 위치 기준 설정 (start 또는 down) |
behavior | HitTestBehavior | HitTestBehavior.opaque | 히트 테스트 시 동작 방식 설정 |
onUpdate | DismissUpdateCallback? | null | 드래그 중에 호출되는 콜백, 상태에 따른 UI 업데이트 등에 사용 |
기본적인 코드 구성은 이렇게 된다.
class _TestState extends State<Test> {
List<int> items = List<int>.generate(10, (int index) => index);
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Dismissible(
background: Container(color: Colors.green,),
key: ValueKey<int>(items[index]),
onDismissed: (direction) {
setState(() {
items.removeAt(index);
});
},
child: ListTile(title: Text('dd'),),
);
},
),
);
}
}
우리가 이 위젯에서 주시해야 할 것은 key 와 onDismissed 인데 key 부터 살펴보겠다.
key
이 위젯에서 정말 중요한 속성이다.
Dismissible 위젯은 내부적으로 애니메이션과 상태 관리를 위해 각 위젯을 고유하게 식별할 수 있는 key가 필요하다. 이 key 는 특히 리스트가 변할 때 어떤 위젯이 제거되었고 어떤 위젯이 남아 있는지를 판단하는 핵심 기준이다.
key: ValueKey<int>(items[index]),
예제에서 만든 이 고유 키는 아이템값(0 - 9) 기반으로 만들어져 있는데 이 키 덕분에 Dismissible 위젯은 어떤 데이터를 나타내고 있는지 정확히 알 수 있다. 그니까 쉽게 말하자면 리스트에서 어떤 아이템이 지워졌는지 또는 남아 있는지를 구분하기 위해 key를 사용한다는 것이다.
지금 이 키는 이렇게 선언이 되어 있을 것이다.
items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; // generate 10 했으니까
이제 여기에서 리스트에 있는 3번째에 있는 아이템을 지운다면
items = [0, 1, 3, 4, 5, 6, 7, 8, 9]; // 3 번째 아이템인 2삭제
이렇게 되는 것이다. 그걸 key 로 받고 있는 것이고 이제 이해가 확실히 되었을 것이다.
onDismissed
이 콜백은 사용자가 해당 아이템을 드래그하여 완전히 스와이프 해서 화면 밖으로 사라지게 했을 때 실행된다. 그니까 땡기는 와중에는 실행 안된다는 소리이다.
여기서 setState() 를 호출하여 상태 갱신하고 해당 index 의 아이템을 리스트에서 삭제해 주는 역할을 하게 된다.
onDismissed: (direction) {
setState(() {
items.removeAt(index); // 좀 위험
});
},
기본 예제에서 이렇게 되어 있어서 똑같이 따라 코드를 작성하긴 했다만 추천하는 방식은 아니다.
이렇게 하면 삭제 시점에서 index가 가리키는 아이템이 바뀌는 위험이 있다. 그래서 애니메이션 도중에 빌드가 일어난다면 items[index]가 이미 삭제된 상태일 수 있다. 그래서 이렇게 바꿔서 사용하길 바란다.
onDismissed: (direction) {
final item = items[index];
setState(() {
items.remove(item);
});
},
참고로 이렇게 새로 만든 item 을 인자값으로 넣지 않고 그냥 remove(index) 를 냅다 박아버린다면 아이템을 삭제한 후 수백 줄의 오류 코드를 볼 수 있을 것이다. (나도 알고 싶지 않았다.)
암튼 간에 이것까지가 필수로 해야 했던 것들이고 나머지 하위 값도 알아보자면 먼저 backgorund 와 secondaryBackgorund 가 있을 것인데 backgorund 는 말 그대로 드래그할 때 뒤에 보이는 배경색을 지정할 수 있는 곳이다. 근데 특이한 게 컬러를 받는 게 아니라 Widget? 을 받기 때문에 넣고 싶은 걸 넣을 수 있다.
그렇다면 secondaryBackgorund 는 뭐냐? 이제 왼쪽이랑 오른쪽이랑 드래그했을 때 색이 다르게 나오게 하고 싶다면 사용하면 된다.
background: Container(color: Colors.green,),
secondaryBackground: Container(color: Colors.red,),
이렇게 하니까 왼쪽은 초록 오른쪽은 빨강이 나온다.
이번에는 이렇게 Dismissible 위젯을 알아보았는데 생각보단 쉽지만은 않은 것 같다. 또 어떻게 보면 되게 쉬운 것 같긴 한데 좀 귀찮은 점이 있는 친구인 것 같다. 암튼 도움이 되었길 바라며 마치겠다.