https://kotlinlang.org logo
#compose
Title
# compose
c

Colton Idle

01/18/2021, 2:31 PM
First time playing around with creating a composable that has a "slot". (took me way longer than I'd like to admit that I had to call
content()
and not just
content
🙃 Does this seem fairly idiomatic?
Copy code
@Composable
fun MyCustomContainer(header: String = "", content: @Composable () -> Unit) {
    Column() {
        if (header.isNotBlank()) {
            Text(text = header)
        }
        content()
    }
}
a

Adam Powell

01/18/2021, 3:24 PM
Add a
modifier
parameter that defaults to the empty
Modifier
and pass it to the root
Column
then consider propagating the
ColumnScope
receiver to
content
c

Colton Idle

01/18/2021, 5:36 PM
@Adam Powell
consider propagating the 
ColumnScope
 receiver to 
content
You lost me there.
a

Adam Powell

01/18/2021, 5:37 PM
Copy code
@Composable fun MyCustomContainer(
  modifier: Modifier = Modifier,
  header: String = "",
  content: @Composable ColumnScope.() -> Unit
) = Column(modifier) {
  if (header.isNotBlank()) {
    Text(header)
  }
  content()
}
the
ColumnScope
receiver will let callers use any of the usual
ColumnScope
child modifiers
c

Colton Idle

01/18/2021, 5:38 PM
Oh. You did that via
content: @Composable ColumnScope.() -> Unit
?
👍 1
👌 1
When I was looking at Button source (in order to reference a slot api) I saw
content: @Composable RowScope.() -> Unit
and I wasn't sure what it was doing, so I just left it as () -> Unit.
a

Adam Powell

01/18/2021, 5:44 PM
you don't have to, but it does pass along the capabilities and tells the caller a little bit about what to expect around the content's layout
c

Colton Idle

01/18/2021, 5:44 PM
Okay. This is basically my commented code as to what I'm doing.
Copy code
//Key points
//1. Modifier goes first as per convention and we pass it down to internal column so those modifiers are propagated to that layout
//2. This uses a "slot api" in order to pass in content for the container
//3. Marking "content" as a Type of ColumnScope allows us to any ColumnScope child modifiers (not sure what this means yet)
@Composable
fun Container(modifier: Modifier = Modifier, header: String = "", content: @Composable ColumnScope.() -> Unit) {
    Column(modifier) {
        if (header.isNotBlank()) {
            Text(text = header)
        }
        content()
    }
}
@Adam Powell if you get a chance. I tried looking up more info/docs on ColumnScope.() and I'm not really sure what it does. You said "you don't have to, but it does pass along the capabilities and tells the caller a little bit about what to expect around the content's layout" What capabilities are we talkin'?
a

Adam Powell

01/18/2021, 10:33 PM
It puts column-specific modifiers like
Modifier.weight
into scope
c

Colton Idle

01/18/2021, 10:39 PM
Aha. So without that, I wouldn't be able to use column specific modifiers since its "type" safe here. Not like xml where you could always set an attribute and 🤞 that the layout will take it into account?
a

Adam Powell

01/18/2021, 10:45 PM
Right. The layout scope is an explicit parameter to the modifier factory by way of the receiver.
c

Colton Idle

01/18/2021, 10:47 PM
Thanks for teaching @Adam Powell 👍