Though Jetpack Compose supplies a variety of parts for creating a gorgeous UI, at some point chances are you’ll discover that your following format must be applied with a customized part. Jetpack Compose for instance doesn’t have a ready-to-use handy part to work with grid-based UI. What we perceive by comfort:
- versatile chance to outline row and column sizes
- сontent placement in any specified location with out the necessity to place neighbors
We wish to have a part that enables us to create UI like within the following picture:
In Jetpack Compose we have already got comparable parts: LazyVerticalGrid
and LazyHorizontalGrid
. Here’s a frequent utilization of LazyHorizontalGrid
:
Look shut however not the identical as what we’d like. Lazy grids function solely with rows and columns depend and place objects sequentially. Whereas we wish to management not solely counts however sizes. As well as, we have to have the chance to put an merchandise in any place.
Primarily based on the lazy grids API, we’ll outline our part API and name it GridPad
:
As a result of we wish to management content material placement our part will handle so as to add objects with Kotlin DSL through merchandise
sections.
Let’s take a better take a look at GridPadCells
. This class accommodates details about row and column sizes.
Let’s go a little bit again and bear in mind what we’d like. We have to have the chance to specify a measurement for every row and column in a grid.
Due to this fact, GridPadCells
cowl all our necessities. You may discover, for storing rowSizes
and columnSizes utilizing ImmutableList
. Because of this implementation of a listing, the compose compiler marks this class as steady and we don’t must mark GridPadCells
with @Immutable
or @Secure
annotation. Why it will be significant? Right here’s what the official documentation says:
Not all courses should be steady, however a category being steady unlocks plenty of flexibility for the compose compiler to make optimizations when a steady kind is being utilized in locations, which is why it’s such an necessary idea for compose.
Right here is a superb article that explains in additional element Jetpack Compose core ideas comparable to stability, skippability, and restartability. I like to recommend studying it to higher perceive the essential ideas of Jetpack Compose and what they’ll have an effect on.
There are two extra courses that we’ve not coated but: GridPadCellSize
and TotalSize
. The GridPadCellSize
is only a container that accommodates details about the scale of a selected row or column:
The TotalSize
is a helper class that accommodates details about the sum of all sorts of sizes for a row or column and is utilized in a measuring stage:
And the ultimate class here’s a builder class. This class is just not essential, but it surely helps to cut back boilerplate code. Our GridPad
requires two lists of sizes, which within the fundamental use case would be the similar. For that cause, we should always create a mutable class with default initialization and with the flexibility to override chosen sizes:
The second main objective that we wish to obtain is placement content material in any cell on the grid with any span width and peak.
Few necessary edge circumstances that we’ll deal with:
- a cell could comprise multiple component
- the content material could overlap with one another
- content material that goes outdoors the grid can be ignored
Right here is the signature of GridPad
:
Let’s have a look intimately at GridPadScope
. GridPadScope
is the DSL scope that limits what customers can put into our composable layouts. Solely content material with the merchandise are acceptable:
Appears to be like fairly straightforward on the highest however is a little bit bit difficult within the particulars. Right here is GridPadScope
definition:
Listed here are two significant issues: @GridPadScopeMarker
and GridPadItemScope
. The @GridPadScopeMarke
is a @DslMarker
:
The GridPadItemScope
is a context receiver:
The above mixture helps to make strict use of our API: a developer can’t place different composables with out wrapping them into an merchandise. Nor can the developer put an merchandise inside one other merchandise. If you need to be taught extra about context receivers I like to recommend you learn this text.
As you may discover, the whole lot that we’ve simply explored is an interface. Let’s have a look intimately at implementations. Earlier than shifting on, bear in mind what the composable lifecycle appears like. For customized format, we have to implement three sub-stages of the format stage:
Thus we have to measure the youngsters, decide the scale of the format and place the content material. Here’s a very top-level of the GridPad
implementation:
The one interface definition isn’t sufficient to implement the logic of including content material. For that cause, we have to have some implementation, and that implementation is GridPadScopeImpl
. Right here is the place all calls from utilizing GridPad
are redirected to the interface implementation:
The GridPadScopeImpl
is sort of a container that collects all emits from top-level DSL, builds a listing to show, and supplies the flexibility to get added composables:
Within the code above, essentially the most vital half is a metamorphosis from DSL name merchandise {}
inside GridPad
to meta-class GridPadContent
that shops data for future measurement and placement.
Let’s return to GridPad
and end the part. After we accumulate all details about placement content material the whole lot that we’d like is correct calculate sizes for every cell, measure composables, and place them into the correct place. Right here we wouldn’t deep dive into placement logic calculation, will concentrate on Jetpack Compose-related API. Step one is to measure kids based on their location and span measurement:
Many of the above code works by calculating boundaries for composables to name the measure for the positioned merchandise.
The final contact after measurement of all kids is to outline the part measurement and place objects:
Loads of work has been executed right here. The above examples may look a bit sophisticated, however Jetpack Compose mixed with Kotlin DSL supplies prospects to implement elegant APIs to your customized layouts. If you end up confronted with an issue, be happy to look into the supply code of already accomplished parts and take inspiration there, it’s the easiest way to be taught one thing new.