Skip to main content

Flexbox Containers

note

This page covers how to convert existing code from the Spec API to the Kotlin API.

For the main Flexbox documentation, refer to the Layout System with Flexbox page.

Rows and Columns, revisited​

As with the Spec API, Row and Column are the primary layout containers used in the Kotlin API.

Differences between the Kotlin API and the Spec API​

When using Row and Column, there are a few important differences between the Spec API and the Kotlin API:

  1. Props of Rows and Columns - props that configure the Row/Column itself, like alignItems or justifyContent, now appear as props directly on the container component. In this way, there is no difference from setting props on any other component.
  2. Common Props - props that configure a particular child's positioning within the context of a Row/Column, like alignSelf or flex, now appear with other common props on the Style passed to that child. This is akin to LayoutParams in vanilla Android in that they must be able to go on any component and are read by the parent.
  3. Children - children are added within a trailing lambda using the child() calls.

The following snippet illustrates the points above:

 Column(alignItems = YogaAlign.CENTER, style = Style.padding(all = 8.dp)) {
child(Text(text = "Foo", style = Style.flex(grow = 1f)))
child(Text(text = "Bar"))
}

Migrating from the Spec API​

Why are Layout Props Now Defined in Two Different Ways?

Without code-generated builders, Litho had to make a distinction between props of the container itself and common props that can be set on children of the container.

For example, alignItems configures the default alignment for children in this container and is only valid on a flexbox container. It's set like a normal component prop on Row/Column.

On the other hand, alignSelf can be respected on any child of a container, whether it's a Text, a Switch, or some custom Component: it's therefore exposed as a common prop via Style.

The benefit of this is that developers can now statically verify all required props are set instead of verifying at runtime (as well as not rely on codegen!).

Flexbox properties cheatsheet​

The following table helps to identify whether to set a layout property directly on the Row/Column or on the Style:

Flexbox PropertyConfigures a Specific Child?Example Kotlin API Usage
justifyContentNoRow(justifyContent = YogaJustify.CENTER)
alignContentNoRow(alignContent = YogaAlign.CENTER)
alignItemsNoRow(alignItems = YogaAlign.CENTER)
wrapNoRow(wrap = YogaWrap.NO_WRAP)
alignSelfYesStyle.alignSelf(YogaAlign.CENTER)
flexBasisYesStyle.flex(basis = 8.dp)
flexBasisPercentYesStyle.flex(basisPercent = 25f)
flexGrowYesStyle.flex(grow = 1f)
flexShrinkYesStyle.flex(shrink = 1f)
marginYesStyle.margin(8.dp)
paddingYesStyle.padding(8.dp)
widthYesStyle.width(50.dp)
heightYesStyle.height(50.dp)
note

A property is set via Style if and only if it configures a specific child!

Example migration​

Below is an example of a simple Component using various layout properties, converted to an equivalent KComponent:

class FlexboxComponent(
private val username: String,
@DrawableRes private val avatarRes: Int,
@DrawableRes private val imageRes: Int
) : KComponent() {
override fun ComponentScope.render(): Component {
return Column {
child(
Row(alignItems = YogaAlign.CENTER, style = Style.padding(all = 8.dp)) {
child(
Image(
drawable = drawableRes(avatarRes),
style = Style.width(36.dp).height(36.dp).margin(start = 4.dp, end = 8.dp)))
child(Text(text = username, textStyle = Typeface.BOLD))
})
child(
Image(
drawable = drawableRes(imageRes),
scaleType = ImageView.ScaleType.CENTER_CROP,
style = Style.aspectRatio(1f)))
}
}
}