Jose Gonzalez
Jose Gonzalez

Reputation: 1478

How to add a list of composables as parameter

Im trying to pass a list of Composables, in this case Columns, as a parameter to later populate a view, for that I'm adding the parameter List<@Composable (ColumnScope.() -> Unit)> on a composable function and populating a List with simple Columns.

The problem I'm having is that the Columns generate a Type mismatch

Required:
List<ColumnScope.() → Unit>
Found:
List<Unit>

Is there a way to achieve this? Here I'll provide my code.

@Composable
fun LotsOfColumns() {
    ColumnListSample(
        myColumns = listOf(
            Column {}, 
            Column {}
        )
    )
}

@Composable
fun ColumnListSample(
    myColumns: List<@Composable (ColumnScope.() -> Unit)>,
    modifier: Modifier = Modifier
) {}

Upvotes: 3

Views: 3960

Answers (3)

Bruce Lee
Bruce Lee

Reputation: 4441

This is how it's declared:

@Composable
fun SettingsRow(
    modifier: Modifier? = null,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
    children: List<@Composable RowScope.() -> Unit>,
    onClick: () -> Unit
)

This is how composable list passed as parameter:

SettingsRow(
    children = listOf(
        { Icon(Icons.Rounded.Done, contentDescription = "Done") },
        {
            Row(modifier = Modifier.weight(1.0f)) {
                Text(text = config.name)
            }
        }
    )
)

This is how the children is used in SettingsScreen composable.

Row(modifier = Modifier.weight(1.0f)) {
    children.map { it ->
        it()
    }
}

Upvotes: 2

Thracian
Thracian

Reputation: 67293

I do this by wrapping @Composable functions inside a data class or a class then pass that class with a List

data class TutorialSectionModel(
    val title: String,
    val action: @Composable (() -> Unit)? = null,
    val description: String,
    val tags: List<String> = listOf(),
    val tagColor: Color = DefaultListColor,
    var expanded: Boolean = false
)

And create a list of that class that contains that Composables and i pass them to my LazyColumn.

val tutorialList = mutableListOf<List<TutorialSectionModel>>()

Use it with LazyColumn

        LazyColumn(

            content = {

                items(
                    items = tutorialList,
                    key = {
                        it.title
                    }
                ) { item: TutorialSectionModel ->

                    var isExpanded by remember(key1 = item.title) { mutableStateOf(item.expanded) }

                    TutorialSectionCard(
                        model = item,
                        onClick = {
                            navigateToTutorial(item.title)
                        },
                        onExpandClicked = {
                            item.expanded = !item.expanded
                            isExpanded = item.expanded
                        },
                        expanded = isExpanded
                    )
                }
            }

You can pass your @Composable (ColumnScope.() -> Unit to a class you created same way.

Maybe not in your question scope, the way wrapping inside a class helps passing this list to a ViewModel and i use this action or Composables as navigation target too instead of writing tens of composable navigation routes.

    // Set navigation route as title of tutorial card
    // and invoke @Composable inside lambda of this card.
    mainViewModel.tutorialList.forEach { list ->
        list.forEach { model ->
            composable(route = model.title) { navBackEntryStack ->
                // This column is used for setting navigation padding since
                // NavHost only has statusBarsPadding to let main screen list have
                // inset at the bottom with WindowInsetsSides.Bottom
              Column(Modifier.navigationBarsPadding()) {
                  // 🔥 These are @Composable screens such as Tutorial2_1Screen()
                  model.action?.invoke()
              }
            }
        }
    }

Upvotes: 4

Remo
Remo

Reputation: 101

@Composable fun LotsOfColumns() {
    ColumnListSample(
        myColumns = listOf(
            { Column {} },
            { Column {} }
        )
    )
}

Upvotes: 4

Related Questions