[Android Compose] Material3 SnackBar 사용법
XML 뷰에선 간단하게 쓸 수 있던 스낵바가 Compose에선 좀 번거롭다. 아래는 스낵바를 사용하는 예시 컴포저블이다.
@Composable
fun SnackBarExample() {
val snackBarHostState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(hostState = snackBarHostState) }
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
Button(
onClick = {
coroutineScope.launch {
snackBarHostState.showSnackbar(
message = "Hello SnackBar",
duration = SnackbarDuration.Short,
actionLabel = "label"
)
}
}
) {
Text("스낵바 표시")
}
}
}
}
프리뷰에서 확인하면 아래와 같다.
인터랙트 모드로 들어와서 버튼을 누르면 하단에 스낵바가 표시된다. 다크모드인 경우 스낵바 배경색과 글자색이 그에 맞춰 변한다.
아래는 디벨로퍼의 스낵바 공식문서다.
https://developer.android.com/develop/ui/compose/components/snackbar?hl=ko
스낵바를 구현하려면 먼저 SnackBarHostState 타입의 SnackBarHost를 만든다. SnackBarHostState는 showSnackbar()를 호출하는 데 사용할 수 있다. 이 정지 함수는 CoroutineScope가 필요하다(rememberCoroutineScope)
컴포즈에서 showSnackbar()는 정지 함수로 구현돼 있다. 그래서 코루틴 스코프를 만들어야 하고, SnackBarHostState를 remember로 기억시키는 처리가 필요하다.
val snackBarHostState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()
그리고 Column 안에 Button을 두고 onClick에서 스낵바를 표시한다.
Button(
onClick = {
coroutineScope.launch {
snackBarHostState.showSnackbar(
message = "Hello SnackBar",
duration = SnackbarDuration.Short,
actionLabel = "label"
)
}
}
)
message는 보다시피 스낵바에 표시할 메시지고 duration은 스낵바의 표시 시간이다. Short, Long, Indefinite 3가지 중 하나를 쓸 수 있다.
actionLabel에는 스낵바 안에서 오른쪽에 표시할 텍스트를 넣을 수 있다. 옵셔널이라 아예 안 쓰거나 null, 공백을 넣으면 표시되지 않는다. 참고로 showSnackbar()의 구현은 아래와 같다.
suspend fun showSnackbar(
message: String,
actionLabel: String? = null,
withDismissAction: Boolean = false,
duration: SnackbarDuration =
if (actionLabel == null) SnackbarDuration.Short else SnackbarDuration.Indefinite
): SnackbarResult
리턴타입이 SnackbarResult인 걸 볼 수 있다. 이 말은 showSnackbar()의 결과를 변수에 담아서 활용할 수도 있단 뜻이다.
Button(
onClick = {
coroutineScope.launch {
val result = snackBarHostState.showSnackbar(
message = "Hello SnackBar",
duration = SnackbarDuration.Short,
actionLabel = "label"
)
when (result) {
SnackbarResult.ActionPerformed -> {
Log.e("snackbar", "actionPerformed")
}
SnackbarResult.Dismissed -> {
Log.e("snackbar", "dismissed")
}
}
}
}
)
ActionPerformed, Dismissed 2종류가 있는데 아래 경우에 호출된다.
- ActionPerformed : actionLabel 버튼 클릭 시 호출
- Dismissed : 스낵바가 자연적으로 사라졌을 때 호출
ActionPerformed에는 undo를 넣어서 뭔가를 삭제한 다음 스낵바를 띄우고 undo 클릭 시 되돌리는 처리를 넣을 수 있겠다. Dismissed에도 필요한 처리를 넣으면 될 것이다.