Layouts can be explained as containers that residence the
Watch objects — this kind of as buttons, textual content fields, photographs, and extra — that we see on an app UI. They outline how views are organized and exhibited on an app UI.
Jetpack Compose, Android’s modern day UI toolkit, delivers some prevalent structure sorts for developers to use. Nonetheless, you can also use Jetpack Compose to generate custom made layouts primarily based on your needs.
Let’s study extra about personalized layouts for Android applications and how to build them employing Jsatisetpack Compose. In this short article:
Why you need to know how to build custom made layouts
Jetpack Compose delivers numerous developer resources for creating quicker Android applications, which include a variety of structure solutions. Sometimes you can implement the structure necessities for an app’s UI utilizing these current layouts in Jetpack Compose.
Having said that, these existing layouts do not normally fulfill job layout necessities. In these types of cases, you need to know how to develop a personalized structure to fit your project’s correct requirements.
Overview of layouts in Jetpack Compose
Some common layouts in Jetpack Compose are:
Box: a format that places its sights on best of yet another
Column: a structure that locations its sights in a vertical sequence
Row: a format that spots its sights in a horizontal sequence
ConstraintLayout: a structure that places its sights relative to some others
Not too long ago,
LazyHorizontalGrid, which had been grid layouts below tests, ended up absolutely introduced.
Along with this update came an interesting new structure named
LazyLayout. This is a layout that only composes and lays out currently needed products — in other terms, goods that can be visible on a device display screen at a place in time.
You can use lazy layouts to establish effective scrollable layouts.
LazyLayout versions include:
LazyList, which displays scrollable lists in:
LazyGrid, which shows scrollable grids in:
I know you have observed the term “lazy” a ton, and no, it does not mean these layouts are unwilling to accomplish their functions (like some of us 🙃). As an alternative, it basically indicates a lazy structure will carry out its functionality only when required. In other words and phrases, it is truly efficient.
This effectiveness is why lazy layouts are utilised for layouts that intend on displaying huge quantity of sights, allowing for them to be quickly organized and scrollable in the sort of lists and grids.
Measures to create a custom layout in Jetpack Compose
For you to correctly fully grasp the system of developing your individual layout, I will use a simple instance. We will develop a format I like to phone a
This format basically areas its sights future to each and every other, transferring on to the following line when the current line is stuffed up. Even so, it starts arranging its sights from the stop place to the commence situation of the screen — in other words and phrases, from right to remaining:
These kinds of a layout is what I truly feel ought to be utilised for Jetpack Compose’s
AlertDialog buttons to satisfy Materials Style recommendations.
At this time, a identical layout is becoming made use of, but it goes from the get started placement to the close situation of the monitor, which does not fulfill these rules. You can obtain the concern I filed on it with IssueTracker.
Much more good posts from LogRocket:
The idea powering Jetpack Compose layouts for Android apps
To display sights on the monitor, Jetpack Compose composes the UI tree of nodes (which symbolize views), lays out each watch in the UI tree, and attracts just about every of them to the display.
For the needs of this article, we are only fascinated in the laying out of sights, because we can deal with producing a tailor made structure through this method. The course of action of laying out the sights inside of a layout transpires in 3 techniques:
- Measuring all sights in the format (i.e. the children)
- Determining what dimensions the layout ought to be
- Inserting the youngsters in just the boundaries of the layout
In Jetpack Compose, laying out sights can be achieved applying the
Structure composable, which is described as:
@Composable inline enjoyment Layout( material: @Composable @UiComposable () -> Device, modifier: Modifier = Modifier, measurePolicy: MeasurePolicy )
information parameter specifies the look at or sights (referred to as
Composables) you want to be in this structure. The
modifier parameter is utilized to define some modifications to the format, which can be handed from the mother or father view or composable.
The most significant section of the code previously mentioned is
MeasurePolicy, which defines the measurement of baby views, the size of the structure, and the placing of the kid views in the structure.
ReverseFlowRow will begin off as this:
@Composable pleasurable ReverseFlowRow( articles: @Composable () -> Device ) = Structure(articles) measurables, constraints -> // measuring young children, structure sizing, and putting children takes spot listed here.
You might see we represented
MeasurePolicy as a lambda. This is doable because
MeasurePolicy is a functional interface.
Also in the code over,
measurables is the record of youngsters that require to be measured, whilst
constraints is the layout boundaries from the father or mother.
Measuring all sights in the custom format
We measure every boy or girl with constraints by contacting
evaluate(constraints) on every single of them. This returns a
Placeable, which corresponds to a youngster layout that can be positioned by its father or mother structure.
val placeables = measurables.map measurable -> // Measure every kid. measurable.evaluate(constraints)
Note that we utilized the parent’s constraints when measuring just about every youngster. This permits every boy or girl to be in a position to the full area in the mum or dad if possible.
Including dimensions constraints to the tailor made layout
Upcoming, we determine the size of the layout by calling the
format() technique and specifying at least its width and top.
structure(constraints.maxWidth, constraints.maxHeight) // Placement of young children happens listed here.
In this article we made use of the optimum width and peak of the parent’s constraint. Consequently, relying on the mum or dad constraints, this layout may well or could not acquire up the entire monitor.
Placing sights inside the structure
Ultimately, we area the measured children, also named
Placeable elements, in the structure by contacting the
This process need to be used if you want to immediately mirror your format when the device’s layout route changes — in other terms, from left-to-proper to suitable-to-left and vice versa.
Notice that you can get the present
LayoutDirection inside of the
format() receiver. This can be handy if you do not want to automatically mirror your structure when a layout route variations, but rather, make your mind up how you want to position your sights in every single layout route.
If you do not want your layout to be routinely mirrored based mostly on layout route, use the
location() process rather.
// Keep track of the x and y co-ordinates we have positioned small children up to. var yPosition = var xPosition = constraints.maxWidth // Put youngsters in the guardian structure. placeables.forEach placeable -> if (placeable.width < xPosition) // There is still enough space in the current row to add the next child. xPosition -= placeable.width else // Space left in the current row is not enough for the child. // Move to the next row. yPosition += placeable.height xPosition = constraints.maxWidth - placeable.width // Position child on the screen. placeable.placeRelative(xPosition, yPosition)
As you can see, we need to keep track of the
y coordinates used to indicate where a placement should start for each child. This will enable us to place one child next to another as well as know when to move on to the next line or row.
Final Jetpack Compose project code for custom Android app layout
Our complete layout will look like this:
@Composable fun ReverseFlowRow( mainAxisSpacing: Dp, crossAxisSpacing: Dp, content: @Composable () -> Unit ) = Structure(information) measurables, constraints -> // 1. The measuring section. val placeables = measurables.map measurable -> measurable.measure(constraints) // 2. The sizing stage. layout(constraints.maxWidth, constraints.maxHeight) // 3. The placement period. var yPosition = var xPosition = constraints.maxWidth placeables.forEach placeable -> if (placeable.width < (xPosition + mainAxisSpacing.roundToPx())) xPosition -= (placeable.width + mainAxisSpacing.roundToPx()) else yPosition += (placeable.height + crossAxisSpacing.roundToPx()) xPosition = constraints.maxWidth - placeable.width - mainAxisSpacing.roundToPx() placeable.placeRelative(xPosition, yPosition)
Did you notice I added two new properties:
crossAxisSpacing? These are used to add spacing between each child in the layout in the horizontal and vertical directions, respectively.
Testing our custom layout
To preview our layout, we can wrap it within a composable function that is annotated with
@Preview. This enables us to run a sample of the layout without the extra configuration required for an Android application. Also, let’s add some text views/composables within our layout to see how it displays them:
@Preview @Composable fun ReverseFlowRowPreview() ReverseFlowRow(mainAxisSpacing = 16.dp, crossAxisSpacing = 16.dp) Text("First", fontSize = 20.sp, style = TextStyle(background = Color.Red)) Text("Second", fontSize = 20.sp, style = TextStyle(background = Color.LightGray)) Text("Third", fontSize = 20.sp, style = TextStyle(background = Color.Blue)) Text("Fourth", fontSize = 20.sp, style = TextStyle(background = Color.Green)) Text("Fifth", fontSize = 20.sp, style = TextStyle(background = Color.Gray)) Text("Sixth", fontSize = 20.sp, style = TextStyle(background = Color.Yellow)) Text("Seventh", fontSize = 20.sp, style = TextStyle(background = Color.Cyan)) Text("Eight", fontSize = 20.sp, style = TextStyle(background = Color.Magenta)) Text("Ninth", fontSize = 20.sp, style = TextStyle(background = Color.DarkGray))
Running the preview yields the following:
Although we used text views/composables in this example, this custom Jetpack Compose layout will work with other Jetpack Compose composables as well. You can also use the concepts and follow the steps we covered in this tutorial to create your own custom layout.
This is pretty much what creating your own layout entails. This example considers a regular case scenario, like the layout required for the buttons of an
AlertDialog, but it can be improved to cater to more case scenarios, such as a situation where children have different sizes.
If you use the
ReverseFlowRow layout we created as is with children of different sizes, there will be some overlap amongst them. Some additional code is needed to accommodate such a case. If you would like to tackle this mini-challenge, post the updated code in the comments below!
I am excited to see your solutions. In the meantime, you can learn more about Jetpack Compose topics such as theming to improve your Android app development skills.