Issue
Is it possible to set the value of a FloatingActionButton's onClick inside of a Scaffold from a screen composable from a NavHost, which is also inside the Scaffold? Here in my example, I want to be able to change the FAB's onClick to do some calculations from a value (name) inside the screen composable, without hoisting the value to the composable where the Scaffold is located (MyActivity()).
@Composable
fun MyActivity() {
val navController = rememberNavController()
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = { /* set this lambda from Screen1 */ }) { ... }
}
) { paddingValues ->
NavHost(
navController = navController,
startDestination = Screen.Screen1.route,
modifier = Modifier.padding(paddingValues)
) {
composable(route = Screen.Screen1.route) {
Screen1()
}
...
}
}
}
@Composable
fun Screen1() {
var name by remember { mutableStateOf(TextFieldValue("") }
TextField(value = name, onValueChange = { name = it })
// Set FAB onClick to do some calculations on name without hoisting the variable
setFabOnClick { name.calculate() }
}
Solution
I'm not sure why you don't want to put this value in the top view. If you do that in your example, updating the text will not cause recomposition of MyActivity, only Screen1 - Compose is smart enough to do that.
In any case, you can create a mutable state to store the handler and update it in Screen1. I use LaunchedEffect because updating the state is a side effect and should not be done directly from the view constructor, also there is no need to do it at every recomposition.
@Composable
fun Screen1(
setFabOnClick: (() -> Unit) -> Unit,
) {
var name by remember { mutableStateOf(TextFieldValue("")) }
TextField(value = name, onValueChange = {name = it})
LaunchedEffect(Unit) {
setFabOnClick { println("$name") }
}
}
@Composable
fun MyActivity() {
val navController = rememberNavController()
val (fabOnClick, setFabOnClick) = remember { mutableStateOf<(() -> Unit)?>(null) }
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = {
fabOnClick?.invoke()
}) {
Icon(Icons.Default.ReportProblem, null)
}
}
) { paddingValues ->
NavHost(
navController = navController,
startDestination = Screen.Screen1.route,
modifier = Modifier.padding(paddingValues)
) {
composable(route = Screen.Screen1.route) {
Screen1(setFabOnClick = setFabOnClick)
}
}
}
}
Answered By - Phil Dukhov
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.