SwipeToDismissBox
구성요소를 사용하면 사용자가 항목을 왼쪽이나 오른쪽으로 스와이프하여 닫거나 업데이트할 수 있습니다.
API 노출 영역
SwipeToDismissBox
컴포저블을 사용하여 스와이프 동작으로 트리거되는 작업을 구현합니다. 주요 매개변수는 다음과 같습니다.
state
: 스와이프 항목에서 계산에 의해 생성된 값을 저장하기 위해 생성된SwipeToDismissBoxState
상태로, 생성 시 이벤트를 트리거합니다.backgroundContent
: 항목 콘텐츠 뒤에 표시되고 콘텐츠를 스와이프할 때 표시되는 맞춤 구성 가능한 컴포저블입니다.
기본 예: 스와이프 시 업데이트 또는 닫기
이 예시의 스니펫은 시작에서 끝으로 스와이프하면 항목을 업데이트하거나 끝에서 시작으로 스와이프하면 항목을 닫는 스와이프 구현을 보여줍니다.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItem( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank, contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .background(Color.Blue) .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( imageVector = Icons.Default.Delete, contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(Color.Red) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } }
코드 관련 핵심 사항
swipeToDismissBoxState
는 구성요소 상태를 관리합니다. 항목과의 상호작용이 완료되면confirmValueChange
콜백을 트리거합니다. 콜백 본문은 가능한 다양한 작업을 처리합니다. 콜백은 구성요소에 닫기 애니메이션을 표시해야 하는지 여부를 나타내는 불리언을 반환합니다. 이 경우:- 항목을 처음부터 끝까지 스와이프하면
onToggleDone
람다를 호출하여 현재todoItem
를 전달합니다. 이는 할 일 항목 업데이트에 해당합니다. - 항목을 끝에서 시작으로 스와이프하면
onRemove
람다를 호출하여 현재todoItem
를 전달합니다. 이는 할 일 항목을 삭제하는 것과 같습니다. it != StartToEnd
: 이 줄은 스와이프 방향이StartToEnd
이 아니면true
을 반환하고, 그렇지 않으면false
를 반환합니다.false
를 반환하면 '전환 완료' 스와이프 후SwipeToDismissBox
가 즉시 사라지지 않아 시각적 확인이나 애니메이션을 사용할 수 있습니다.
- 항목을 처음부터 끝까지 스와이프하면
SwipeToDismissBox
는 각 항목에서 가로 스와이프 상호작용을 사용 설정합니다. 쉬는 상태에서는 구성요소의 내부 콘텐츠가 표시되지만 사용자가 스와이프를 시작하면 콘텐츠가 사라지고backgroundContent
이 표시됩니다. 일반 콘텐츠와backgroundContent
모두 상위 컨테이너의 전체 제약 조건을 가져와 렌더링합니다.content
가backgroundContent
위에 그려집니다. 이 경우:backgroundContent
는SwipeToDismissBoxValue
를 기반으로 배경 색상이 있는Icon
로 구현됩니다.Blue
StartToEnd
스와이프 시: 할 일 항목 전환Red
EndToStart
스와이프 시 — 할 일 항목 삭제Settled
의 배경에는 아무것도 표시되지 않습니다. 항목을 스와이프하지 않으면 배경에 아무것도 표시되지 않습니다.- 마찬가지로 표시되는
Icon
는 스와이프 방향에 맞게 조정됩니다. StartToEnd
: 할 일 항목이 완료되면CheckBox
아이콘이, 완료되지 않으면CheckBoxOutlineBlank
아이콘이 표시됩니다.EndToStart
는Delete
아이콘을 표시합니다.
@Composable private fun SwipeItemExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItem( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
코드 관련 핵심 사항
mutableStateListOf(...)
는TodoItem
객체를 포함할 수 있는 관찰 가능한 목록을 만듭니다. 이 목록에 항목이 추가되거나 삭제되면 Compose는 이 항목에 종속된 UI 부분을 재구성합니다.mutableStateListOf()
내에서 4개의TodoItem
객체가 각각의 설명('Pay bills', 'Buy groceries', 'Go to gym', 'Get dinner')으로 초기화됩니다.
LazyColumn
는 세로로 스크롤되는todoItems
목록을 표시합니다.onToggleDone = { todoItem -> ... }
는 사용자가 객체를 완료로 표시할 때TodoListItem
내에서 호출되는 콜백 함수입니다.todoItem
의isItemDone
속성을 업데이트합니다.todoItems
는mutableStateListOf
이므로 이 변경사항은 리컴포지션을 트리거하여 UI를 업데이트합니다.onRemove = { todoItem -> ... }
는 사용자가 항목을 삭제할 때 트리거되는 콜백 함수입니다.todoItems
목록에서 특정todoItem
를 삭제합니다. 이렇게 하면 재구성이 발생하고 항목이 표시된 목록에서 삭제됩니다.- 항목이 닫힐 때 수정자의
placementSpec
가 호출되도록 각TodoListItem
에animateItem
수정자가 적용됩니다. 이렇게 하면 항목 삭제와 목록의 다른 항목 재정렬이 애니메이션으로 표시됩니다.
결과
다음 동영상에서는 앞의 스니펫에 나온 기본 스와이프하여 닫기 기능을 보여줍니다.
전체 샘플 코드는 GitHub 소스 파일을 참고하세요.
고급 예: 스와이프 시 배경 색상 애니메이션
다음 스니펫은 위치 기준점을 통합하여 스와이프 시 항목의 배경 색상을 애니메이션 처리하는 방법을 보여줍니다.
data class TodoItem( val itemDescription: String, var isItemDone: Boolean = false )
@Composable fun TodoListItemWithAnimation( todoItem: TodoItem, onToggleDone: (TodoItem) -> Unit, onRemove: (TodoItem) -> Unit, modifier: Modifier = Modifier, ) { val swipeToDismissBoxState = rememberSwipeToDismissBoxState( confirmValueChange = { if (it == StartToEnd) onToggleDone(todoItem) else if (it == EndToStart) onRemove(todoItem) // Reset item when toggling done status it != StartToEnd } ) SwipeToDismissBox( state = swipeToDismissBoxState, modifier = modifier.fillMaxSize(), backgroundContent = { when (swipeToDismissBoxState.dismissDirection) { StartToEnd -> { Icon( if (todoItem.isItemDone) Icons.Default.CheckBox else Icons.Default.CheckBoxOutlineBlank, contentDescription = if (todoItem.isItemDone) "Done" else "Not done", modifier = Modifier .fillMaxSize() .drawBehind { drawRect(lerp(Color.LightGray, Color.Blue, swipeToDismissBoxState.progress)) } .wrapContentSize(Alignment.CenterStart) .padding(12.dp), tint = Color.White ) } EndToStart -> { Icon( imageVector = Icons.Default.Delete, contentDescription = "Remove item", modifier = Modifier .fillMaxSize() .background(lerp(Color.LightGray, Color.Red, swipeToDismissBoxState.progress)) .wrapContentSize(Alignment.CenterEnd) .padding(12.dp), tint = Color.White ) } Settled -> {} } } ) { OutlinedCard(shape = RectangleShape) { ListItem( headlineContent = { Text(todoItem.itemDescription) }, supportingContent = { Text("swipe me to update or remove.") } ) } } }
코드 관련 핵심 사항
drawBehind
는Icon
컴포저블의 콘텐츠 뒤에 있는 캔버스에 직접 그립니다.drawRect()
는 캔버스에 직사각형을 그리고 그리기 범위의 전체 경계를 지정된Color
로 채웁니다.
- 스와이프하면
lerp
를 사용하여 항목의 배경 색상이 원활하게 전환됩니다.StartToEnd
에서 스와이프하면 배경 색상이 밝은 회색에서 파란색으로 점진적으로 변경됩니다.EndToStart
에서 스와이프하면 배경 색상이 밝은 회색에서 빨간색으로 점진적으로 변경됩니다.- 한 색상에서 다른 색상으로의 전환 정도는
swipeToDismissBoxState.progress
에 따라 결정됩니다.
OutlinedCard
: 목록 항목 사이에 미묘한 시각적 구분을 추가합니다.
@Composable private fun SwipeItemWithAnimationExample() { val todoItems = remember { mutableStateListOf( TodoItem("Pay bills"), TodoItem("Buy groceries"), TodoItem("Go to gym"), TodoItem("Get dinner") ) } LazyColumn { items( items = todoItems, key = { it.itemDescription } ) { todoItem -> TodoListItemWithAnimation( todoItem = todoItem, onToggleDone = { todoItem -> todoItem.isItemDone = !todoItem.isItemDone }, onRemove = { todoItem -> todoItems -= todoItem }, modifier = Modifier.animateItem() ) } } }
코드 관련 핵심 사항
- 이 코드에 관한 주요 사항은 동일한 코드 스니펫을 설명하는 이전 섹션의 주요 사항을 참고하세요.
결과
다음 동영상에서는 애니메이션 배경 색상이 있는 고급 기능을 보여줍니다.
전체 샘플 코드는 GitHub 소스 파일을 참고하세요.