Skip to main content

Layout and Styling

note

Within Litho, lists are implemented using the Lazy Collection API.

Layouts​

Lazy Collections are available as follows:

  • LazyList - arranged as a sequential list.
  • LazyGrid - arranged as a grid with the number of columns specified by the columns parameter.
  • LazyStaggeredGrid - arranged into columns where children are inserted into the first column that has space.

Horizontal lists​

To make a Lazy Collection horizontal, set the parameter orientation = RecyclerView.HORIZONTAL. By default, it's necessary to specify a height, such as style = Style.height(100.dp), as follows:

class HScrollFixedHeight : KComponent() {
override fun ComponentScope.render(): Component =
LazyList(
orientation = RecyclerView.HORIZONTAL,
style = Style.height(100.dp),
) { /* Add children */
}
}

Defining height behavior​

The height behavior of a horizontal list is determined by the crossAxisWrapMode parameter.

Possible values are:

  • NoWrap (default) - by default, a horizontal list requires a height to provided via the style parameter, either as an explicit height (Style.height()) or as layout constraints (such as Style.flex()).
  • MatchFirstChild - the horizontal scroll height will be tied to the height of the first child.
  • Dynamic - the horizontal scroll height will match the tallest item in the list.
caution

CrossAxisWrapMode.Dynamic requires measuring all the components in the list. This is inefficient and should be avoided if possible.

Spacing​

To add spacing around and between items, use LinearSpacing. This will create an ItemDecorator that will be applied to the underlying RecyclerView. It automatically takes care of edge cases including equality checks (to avoid unnecessary layouts), orientation, and layout direction handling:

class LinearSpacingExample : KComponent() {
override fun ComponentScope.render(): Component =
LazyList(
itemDecoration = LinearSpacing(start = 10.dp, between = 5.dp),
) { /* Add children */
}
}

Sticky headers​

To make a child 'sticky', specify the parameter isSticky = true. This will cause the child to stick to the top of the Lazy Collection rather than being scrolled out of the viewport.

class StickyHeader(val names: List<String>) : KComponent() {
override fun ComponentScope.render(): Component {
val namesGroupedByFirstLetter = names.groupBy { it.first() }
return LazyList {
namesGroupedByFirstLetter.forEach { (firstLetter, names) ->
child(id = firstLetter, isSticky = true, component = Text("$firstLetter"))
children(items = names, id = { it }) { Text(it) }
}
}
}
}