androidnavigationparameter-passingcomposablenavgraph

Jetpack Compose NavGraphBuilder uses composable as a method parameter. How?


This is from an Android compass app project at https://github.com/AkarshGuptaa/Compass.git which compiles and runs without bugs

I'm wanting to know how compassComposable: @Composable () -> Unit is passed to the HomeScreen composable function when none of the calls to this function provide the "compassComposable" parameter

Here is a portion of the code

NavHost(
    modifier = modifier,
    navController = navController,
    startDestination = startDestination,
){
    composable(ScreenRoutes.Home.name){
        HomeScreen( // <- call to home screen (without compassComposable parameter)
        degrees = degrees,
        isMagneticFieldSensorPresent = isMagneticFieldSensorPresent,
        onMenuClick = { navController.navigate(ScreenRoutes.WidgetSelection.name )}
        ){..}
        ..       
    }

    composable(ScreenRoutes.WidgetSelection.name){ // but somehow this is correctly passed to the HomeScreen composable function HOW??
        ..
        WidgetScreen( ..
        )
    }
}

But the HomeScreen Composable fun has a compassComposable parameter that is never supplied.

@Composable
fun HomeScreen(
     modifier: Modifier = Modifier,
     degrees: Int, // observe this
     isMagneticFieldSensorPresent: Boolean,
     onMenuClick: () -> Unit = {},
     compassComposable: @Composable () -> Unit // Correctly points to the right navGraph composable but since it is never passed to the function when called, how does this happen?? 
     )  {
        ...
        compassComposable() // correctly displays the selected compass widget
        ..
        }


I've tried to trace it through the debugger but the "magic" seems to be happening in the background

Solution

  • This is made possible with the help of trailing lambda syntax on Kotlin

    Trailing lambda as the name says, is a lamda function that is the last (trailing) parameter in a function

    So, let's say you have a function foo

    fun foo(a:Int, b:Int, c:()->Unit){
       // Do something
    }
    

    If you notice, we have a lambda function as the last parameter, so you can call this like so, right?

    fun main(){
      foo(a= 1, b=2 ,c ={
           // Do something 
            })
    }
    

    You can make this even more visually easy to read by the trailing lambda syntax like so

    fun main(){
      foo(a=1, b=2){
        // This is provided to the parameter C 
    
        // Do something 
      }
    }
    

    Good read on the docs can be found here