HelloCW
HelloCW

Reputation: 2255

How can I convert a val to a fun when I use Jetpack Compose in Kotlin?

The Code A is from the official sample project.

I think I use a function instead of the val background, but the Code B is wrong.

How can I convert a val to a fun when I use Jetpack Compose in Kotlin?

Code A

@Composable
fun NiaApp(
    windowSizeClass: WindowSizeClass,
    appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
    NiaTheme {
        val background: @Composable (@Composable () -> Unit) -> Unit =
            when (appState.currentDestination?.route) {
                ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
                else -> { content -> NiaBackground(content = content) }
            }

        background {
            Scaffold(
                ...
            ) { padding ->
                Row(
                   ...
                ) {
                  ...
            }
        }
    }
}

Code B

@Composable
fun NiaApp(
    windowSizeClass: WindowSizeClass,
    appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
    NiaTheme {
         @Composable
         fun background(aa: @Composable () -> Unit){
            when (appState.currentDestination?.route) {
                ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
                else -> { content -> NiaBackground(content = content) }
            }
        }

        background {
            Scaffold(
                ...
            ) { padding ->
                Row(
                   ...
                ) {
                  ...
            }
        }
    }
}

Added content:

To Arpit Shukla: Thanks!

The Code C is based Code A val background: @Composable (@Composable () -> Unit) -> Unit... .

Your Code D is right, but why is Code C wrong ?

Code C

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
    when (appState.currentDestination?.route) {
        ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
        else -> { content -> NiaBackground(content = content) }
    } 
}

Code D

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
    when (appState.currentDestination?.route) {
        ForYouDestination.route -> NiaGradientBackground(content = content)
        else -> NiaBackground(content = content)
    }
}

Added content again:

To Arpit Shukla: Thanks!

By your way, Code E and Code F can't be compiled.

Code E

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
    when (appState.currentDestination?.route) {
        ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
        else -> { content -> NiaBackground(content = content) }
    }(content) // Call the lambda
}

Code F

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit -> NiaGradientBackground(content = content)
) {
   when (appState.currentDestination?.route) {
        ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
        else -> { content -> NiaBackground(content = content) }
    }(content) // Call the lambda
}

New content:

To Arpit Shukla: Thanks!

By your way, Code G can't be compiled yet, I get the following error.

@Composable invocations can only happen from the context of a @Composable function

Code G

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
    when (appState.currentDestination?.route) {
        ForYouDestination.route -> { content1: @Composable () -> Unit -> NiaGradientBackground(content = content1) }
        else -> { content1: @Composable () -> Unit -> NiaBackground(content = content1) }
    }(content) // Call the lambda
}

Upvotes: 0

Views: 560

Answers (3)

Arpit Shukla
Arpit Shukla

Reputation: 10493

You can try this:

@Composable
fun NiaApp(
    windowSizeClass: WindowSizeClass,
    appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
    NiaTheme {
        Background(appState) {
            Scaffold(
                ...
            ) { padding ->
                Row(
                   ...
                ) {
                  ...
            }
        }
    }
}

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
    when (appState.currentDestination?.route) {
        ForYouDestination.route -> NiaGradientBackground(content = content)
        else -> NiaBackground(content = content)
    }
}

Edit: Your when statement in Code C only creates a lambda function which when invoked will call the composables. You need to call that lambda too to see any effect:

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
   when (appState.currentDestination?.route) {
        ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
        else -> { content -> NiaBackground(content = content) }
    }(content) // Call the lambda
}

Note: I haven't run this code but the compiler may give you an error here saying that it is unable to infer type for the content variable in the lambda. In that case you will have to explicitly provide the type: content: @Composable () -> Unit -> NiaGradientBackground(content = content)

Anyway, this is too much of unnecessary effort here and is only making the code more complex than the original one. Code D is much straightforward.

Edit: In code G, the lambda is by default not a composable function, you can't call composables inside it. Just putting @Composable in front of the lambda doesn't work, you need to explicitly provide the type for the entire when expression.

@Composable
fun Background(
    appState: NiaAppState,
    content: @Composable () -> Unit
) {
    val background: @Composable (@Composable () -> Unit) -> Unit =
        when (appState.currentDestination?.route) {
            ForYouDestination.route -> { content -> NiaGradientBackground(content = content) }
            else -> { content -> NiaBackground(content = content) }
        }
    background(content)
}

We reached to the same code we started with which you wanted to simplify. Code D is the best solution in my opinion.

Upvotes: 4

Roman Y
Roman Y

Reputation: 335

Well, something like this:

@Composable
fun NiaApp(
        windowSizeClass: WindowSizeClass,
        appState: NiaAppState = rememberNiaAppState(windowSizeClass) ) {
        NiaTheme {
            background(appState)() {
                Scaffold(
                    ...
                ) { padding ->
                  }
            }     
        }
}
    
@Composable
fun background(appState: NiaAppState): @Composable (@Composable () -> Unit) -> Unit =
        when (appState.currentDestination?.route) {
            ForYouDestination.route -> { content -> 
                NiaGradientBackground(content = content) }
                else -> { content -> NiaBackground(content = content) }
            } 

Upvotes: 1

MohammadBaqer
MohammadBaqer

Reputation: 1415

just cut your Background composable function and paste it outside of the NiaApp composable function

@Composable
fun NiaApp(
    windowSizeClass: WindowSizeClass,
    appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
    NiaTheme {
        background {
            Scaffold(
                ...
            ) { padding ->
                Row(
                   ...
                ) {
                  ...
            }
        }
    }    
}

@Composable
fun background(aa: @Composable () -> Unit){
    when (appState.currentDestination?.route) {
        ForYouDestination.route -> { content -> 
            NiaGradientBackground(content = content) }
            else -> { content -> NiaBackground(content = content) }
        }
}

Upvotes: 0

Related Questions