SwipeToDismiss(밀어서 삭제) 방식은 리스트에서 아이템을 삭제하거나, 좋아요나 플레이리스트 등 특정 그룹에 추가하는 기능을 구현할 때 용이하다.
Jetpack Compose에서는 이를 쉽게 제작할 수 있도록 SwipeToDismiss 라는 Composable 함수를 지원한다.
작성 방법이 쉽기 때문에 금방 따라 작성할 수 있다.
val dismissState = rememberDismissState(confirmStateChange = {
if (it == DismissValue.DismissedToStart) {
/**
* Dismiss 되었을 때 작업할 코드 작성
*/
}
true
})
SwipeToDismiss(state = dismissState, directions = setOf(
DismissDirection.EndToStart
), dismissThresholds = { direction ->
FractionalThreshold(0.4f)
}, background = {
val color by animateColorAsState(
when (dismissState.targetValue) {
DismissValue.Default -> Color.White
else -> Color.Red
}
)
val scale by animateFloatAsState(
if (dismissState.targetValue == DismissValue.Default) 0.75f else 1f
)
Box(
modifier = Modifier
.fillMaxSize()
.background(color)
.padding(horizontal = Dp(20f)),
contentAlignment = Alignment.CenterEnd
) {
Icon(
Icons.Default.Delete,
contentDescription = "Delete Icon",
modifier = Modifier.scale(scale)
)
}
}, dismissContent = {
Card(
shape = RoundedCornerShape(0.dp),
elevation = animateDpAsState(
if (dismissState.dismissDirection != null) 4.dp else 0.dp
).value
) {
/**
* 원본 콘텐츠 구성가능한함수 작성
*/
}
})
state
: 앞선 코드에서 선언한 DismissState 에서 confirmStateChange
콜백 함수를 통해 SwipeToDismiss Composable 함수의 Dismiss 상태를 추적할 수 있다.
DismissValue.DismissedToStart
: 오른쪽에서 왼쪽으로 Dismiss 됨
DismissValue.DismissedToEnd
: 왼쪽에서 오른쪽으로 Dismiss 됨
Default
: Dismiss 되지 않은 상태
의도한 방향으로 Dismiss 된 경우 리스트 아이템 삭제 등 작업을 수행하면 된다.
dismissThresholds
: Dismiss 되는 임계치 이다. 0.0f ~ 1.0f, ex) 0.5f 로 설정한 경우 50% 이상 Swipe 된 경우 Dismiss 된 것으로 간주
background
: Dismiss 된 경우 후방에 위치하는(본 컨텐츠 뒤에 위치하는) Composable 함수. 이전에 선언한 DismissState에 따라 애니메이션을 삽입 할 수 있다.
dismissContent
: 본 컨텐츠가 되는 Composable 함수 (Dismiss 되기 전까지 보여지는 컨텐츠)
아이템 삭제시 자연스럽게 하기
DismissedToStart등 State 반응시 즉시 아이템을 제거하는 등의 작업을 하게 되면 UI 가 부자연스럽다.
이를 해결하기 위해, SwipeToDismiss의 modifier에 animateItemPlacement()
를 적용하면 리스트에서 아이템이 제거 되었을 때 보다 자연스럽게 반응한다.
또한 다음과 같이 일정 시간 동안 딜레이를 준 뒤 본 작업을 수행 하는 것이 더 보기 좋다.
val dismissState = rememberDismissState(confirmStateChange = {
if (it == DismissValue.DismissedToStart) {
CoroutineScope(Dispatchers.Main).launch {
delay(400)
viewModel.remove(resource)
}
}
true
})
답글 남기기