Leave a rating/review
Notes: 11. Build Custom Dialogs
The student materials have been reviewed and are updated as of September 2022.
Demo
You can also build custom dialogs in compose! Let’s build one to be able to add reading lists. Create a new file within the readingLists.ui package, named ReadingListDialogs, and add the following code:
@Composable
fun AddReadingList(
onAddList: (String) -> Unit = {},
onDismiss: () -> Unit = {}
) {
val inputState = remember { mutableStateOf("") }
Dialog(onDismissRequest = onDismiss) {
val shape = RoundedCornerShape(16.dp)
}
}
Notice how you’re using the Dialog component. The dialog lets you define a dismiss request lambda, to trigger when you close the dialog.
You also define a content lambda, which describes the entire UI tree of the dialog, so it’s completely custom.
Now add the following code, to define a card with a text, a single input field and a button:
Column(
modifier = Modifier.background(
MaterialTheme.colors.surface,
shape = shape
).border(width = 1.dp, color = MaterialTheme.colors.primary, shape = shape),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
}
Now that you’ve defined a nice Column with a border and a material shape, you can add the UI controls.
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(id = R.string.add_reading_list_title),
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
InputField(
label = stringResource(id = R.string.reading_list_name_hint),
value = inputState.value,
isInputValid = inputState.value.isNotEmpty(),
onStateChanged = { newValue -> inputState.value = newValue }
)
And finally, after adding the input field and the title, add the confirm button.
ActionButton(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = R.string.add_reading_list_button_text),
isEnabled = inputState.value.isNotEmpty(),
onClick = { onAddList(inputState.value) },
)
The code and the UI building process should be familiar to you by now. You have a single card, a text to describe what the dialog is about, and an input field for the name of the new reading list. And finally, you add a button to confirm the reading list name.
Now let’s fill in the ReadingListFragment, with the new action handlers. Open the ReadingListFragment file, and add the following code:
val readingListsState = mutableStateOf(emptyList<ReadingListsWithBooks>())
private val _isShowingAddReadingListState = mutableStateOf(false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loadReadingLists()
}
private fun loadReadingLists() {
lifecycleScope.launch {
readingListsState.value = repository.getReadingLists()
}
}
You add the state, and load the lists in onViewCreated().
Now add the Box to be able to display the dialog over the lists, and the logic that handles the dialog:
val readingLists = readingListsState.value
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
ReadingLists(readingLists, onItemClick = { onItemSelected(it) })
val isShowingAddList = _isShowingAddReadingListState.value
if (isShowingAddList) {
AddReadingList(
onDismiss = { _isShowingAddReadingListState.value = false },
onAddList = { name ->
addReadingList(name)
_isShowingAddReadingListState.value = false
})
}
}
Using the Box, you let the dialog draw over the list. Now finish off the dialog actions.
@Composable
fun AddReadingListButton() {
FloatingActionButton(onClick = {
_isShowingAddReadingListState.value = true
}) {
Icon(asset = Icons.Default.Add)
}
}
fun addReadingList(readingListName: String) {
lifecycleScope.launch {
repository.addReadingList(ReadingList(name = readingListName, bookIds = emptyList()))
readingListsState.value = repository.getReadingLists()
}
}
That’s it! You show the dialog only if the Boolean flag is true, and add the appropriate handles for the state. To do that, you use the Box again, and centered alignment. You also show the dialog you just defined, to let the user put in the reading list name.
Now build & run the app, and finally add some reading lists to your app.
[Build & run, add reading lists]
Awesome! In the next few episodes, you’ll learn how to reuse your code even more, and how to style your app, to make it even nicer! :]