Unit> = list" /> Unit> = list" /> Unit> = list"/>

Adding lists of Composables?

168 Views Asked by At

I have found that

val list: List<@Composable ()-> Unit> = listOf({Text("Cat")}, {Text("Dog")})

works, but

val list: List<@Composable ()-> Unit> = listOf({Text("Cat")}) + listOf({Text("Dog")})

produces the error "@Composable invocations can only happen from the context of a @Composable function" on the first Text().

Why is it that adding lists works fine with things like

val list: List<String> = listOf("Cat") + listOf("Dog")

but doesn't seem to work with Composables? Is there a way how I can add lists of Composables to each other?

2

There are 2 best solutions below

0
Muhammad Umar On BEST ANSWER

The difference in behavior between the two scenarios is related to how Jetpack Compose handles the @Composable functions and the context in which they are invoked.

In the first scenario:

val list: List<@Composable ()-> Unit> = listOf({Text("Cat")}, {Text("Dog")})

Both Text("Cat") and Text("Dog") are wrapped in @Composable lambda expressions within the list. When you use the list directly, the lambda expressions are invoked within the context of a @Composable function.

In the second scenario:

val list: List<@Composable ()-> Unit> = listOf({Text("Cat")}) + listOf({Text("Dog")})

Here, you are using the + operator to concatenate two lists. The resulting list contains two @Composable lambda expressions, but they are not automatically invoked within a @Composable context.

To Better understand, try with this example

@Composable
fun MainView() {
    val list: List<@Composable () -> Unit> = combineComposableLists()

    // Important: Render each composable in the combined list
    list.forEach { composable -> composable() }
}

@Composable
fun combineComposableLists(): List<@Composable () -> Unit> {
    val list1: List<@Composable () -> Unit> = getList1()
    val list2: List<@Composable () -> Unit> = getList2()

    return list1 + list2
}

@Composable
fun getList1(): List<@Composable () -> Unit> {
    return listOf(
        { Text("Cat") },
        { Text("Dog") }
    )
}

@Composable
fun getList2(): List<@Composable () -> Unit> {
    return listOf(
        { Text("Fish") },
        { Text("Bird") }
    )
}
0
MaxD On

Just a quick update what I ended up on: Since I really wanted everything in a single line, I specified the type for each list separately.

val list = listOf<@Composable ()-> Unit>({Text("Cat")}) + listOf<@Composable ()-> Unit>({Text("Dog")})

Maybe not the most elegant solution, but good enough for me.