[Android] 뒤로가기 할 때 AlertDialog 띄우기 in Compose

1 분 소요

어느 화면에서 뒤로가기 버튼을 눌렀을 때 다이어로그를 띄워 한 번 더 확인하는 것을 compose에서 구현하고 싶었습니다. 구현한 결과물을 먼저 보이겠습니다.

preview

이는 사용자가 게시글을 수정하는 등의 작업을 할 때 실수로 뒤로가기 버튼을 눌러 작성한 내용을 잃지 않도록 하기 위한 방법입니다.

이를 위해서는 BackHandler가 필요합니다. 이 컴포저블 함수는 콜백을 등록하여 뒤로가기 액션 대신 콜백을 실행할 수 있게 해줍니다.

이를 활용하여 RecheckHandler라는 새로운 컴포저블을 만들어 다양한 곳에서 재활용할 수 있도록 하겠습니다. 앞서 설명한 BackHandler를 이용하여 아래와 같이 구현합니다.

@Composable
fun RecheckHandler(
    enableRechecking: Boolean = true
) {
    BackHandler(enableRechecking) {
        ...
    }
}


이제 뒤로가기 버튼을 누르면 다이어로그를 보여야 합니다. Compose에서는 상태를 이용하여 다이어로그를 띄우면 됩니다. 적용하면 아래와 같습니다.

@Composable
fun RecheckHandler(
    enableRechecking: Boolean = true
) {
    var showAlertDialog by remember { mutableStateOf(false) }

    if (showAlertDialog) {
        RecheckDialog(
            onDismissRequest = { showAlertDialog = false },
            onOkClick = { /* TODO implement */ }
        )
    }

    BackHandler(enableRechecking) {
        showAlertDialog = true
    }
}

@Composable
fun RecheckDialog(onOkClick: () -> Unit, onDismissRequest: () -> Unit) {
    AlertDialog(
        title = {
            Text(text = stringResource(R.string.recheck_dialog_title))
        },
        text = {
            Text(text = stringResource(R.string.recheck_dialog_text))
        },
        onDismissRequest = onDismissRequest,
        dismissButton = {
            TextButton(onClick = onDismissRequest) {
                Text(stringResource(R.string.cancel))
            }
        },
        confirmButton = {
            TextButton(onClick = onOkClick) {
                Text(stringResource(R.string.ok))
            }
        }
    )
}


이제 확인 버튼을 누른 경우를 처리하면 됩니다. 이때 LocalOnBackPressedDispatcherOwner를 이용한다면 BackHandler의 콜백이 호출되기 때문에 다른 방법을 이용해야 합니다. 저는 아래와 같이 navigateUp을 매개변수로 전달받을 수 있게 하여 상황에 맞게 뒤로 갈 수 있도록 했습니다. 아래가 구현 완성본입니다.

@Composable
fun RecheckHandler(
    navigateUp: () -> Unit,
    enableRechecking: Boolean = true
) {
    var showAlertDialog by remember { mutableStateOf(false) }

    if (showAlertDialog) {
        RecheckDialog(
            onDismissRequest = { showAlertDialog = false },
            onOkClick = { navigateUp() }
        )
    }

    BackHandler(enableRechecking) {
        showAlertDialog = true
    }
}

...


사용법

아래와 같이 해당 컴포저블 함수 내에 위치시면 됩니다.

@Composable
fun SomeScreen(
    navigateUp: () -> Unit,
    ...
) {
    RecheckHandler(
        navigateUp = navigateUp,
        enableRechecking = someValue
    )

    Scaffold() {
      ...
    }
}


Activity finish 이용

다이어로그의 확인 버튼을 눌렀을 때 Activity를 끝내야 할 경우 다음과 같이 Activityfinish 함수를 전달하면 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    ...

    setContent {
        SomeScreen(navigateUp = ::finish, ...)
    }
}


Compose의 NavController 이용

간단히 NavControllernavigateUp를 전달하면 됩니다.

SomeScreen(navigateUp = navController::navigateUp, ...)

댓글남기기