Dialog는 AlertDialog를 통해 Material 디자인의 다이얼로그를 띄울 수 있다.
아래의 코드를 보자
@Composable
fun DialogEx() {
var openDialog by remember {
mutableStateOf(false)
}
var counter by remember {
mutableStateOf(0)
}
Column {
Button(onClick = { openDialog = true }) {
Text("다이얼로그 열기")
}
Text("카운터 $counter")
}
if (openDialog) {
AlertDialog(
onDismissRequest = { openDialog = false },
confirmButton = {
Button(
onClick = { counter++ }
) {
Text("더하기")
}
},
dismissButton = {
Button(onClick = {openDialog = false}){
Text(text = "끄기")
}
},
title = {Text("title!")},
text = {Text("text!!!")}
)
}
}
보면 Dialog를 dismiss하거나 끄는 코드가 따로 존재하지 않는다.
다만 state를 변경시켜, 리 렌더링 과정에서 이 state가 false면 dialog를 띄우지 않게 되므로, 사실상 dismiss와 같은 역할을 한다.
onDissmissRequest
는 모달 창 밖 영역 화면을 누를 때 발생할 동작을 넣는 곳이다.
Material이 아닌 순수한 형태의 Dialog를 원하면 AlertDialog 대신 그냥 Dialog를 띄우면 된다.
참고로 Dialog를 쓴다면 내부의 요소들을 넣을 때 꼭 Surface 안에 넣어줘야 dialog 배경이 딤 처리 되지 않는다.
Snackbar composable이 존재한다. 하지만 이를 띄우고, 애니메이션 효과를 주고, 하는 등의 작업이 우리 몫이 되기 때문에, 게다가 snackbar는 suspend 하게 동작하기 때문에 이렇게 하지 않고
ScaffoldState.snackbarHostState
를 사용하여 구현한다.
fun SnackbarEx(){
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = {SnackbarHost(hostState = snackbarHostState)},
content = {
Modifier.padding(paddingValues = it)
scope.launch {
snackbarHostState.showSnackbar(
message = "ddd",
actionLabel = "닫기",
duration = SnackbarDuration.Short
)
}}
)
}
rememberCoroutineScope는 컴포지션 인식 범위를 확보하여 컴포저블 외부에서 코루틴 실행을 위한 코루틴 스코프이다. 즉, recomposition이 일어날 때 coroutine을 삭제해준다.
SnackbarHostState 현재 snackbar의 state를 관리하기 위해 만들어주는 것이 snackbarHostState이다. 이를 통해 snackbar가 시간이 지났을 때 dismiss가 될 수 있다.
사실 위의 코드와 같이 composition에서 직접적으로 coroutine을 호출하면 안된다. LauncedEffect를 통해 값이 바뀔 때에만 호출하도록 제어를 해줘야 한다.
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SnackbarEx() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
content = {
Modifier.padding(paddingValues = it)
LaunchedEffect(snackbarHostState) {
scope.launch {
snackbarHostState.showSnackbar(
message = "ddd",
actionLabel = "닫기",
duration = SnackbarDuration.Short
)
}
}
}
)
}