Table of Contents
In the previous MAD Skills Compose Basics article, you learned about the building blocks of UI in Compose: composable functions. Now, it’s time to learn about the powerful toolkit of UI components that ship with Compose enabling you to build rich UIs and interactions.
If you’ve got any questions so far from this series on Compose Basics, we will have a live Q&A session on October 13th. Leave a comment here, on YouTube, or using #MADCompose on Twitter to ask your questions.
So far we’ve looked at how to build a portion of the single choice question screen in Jetsurvey, one of our Compose samples. Let’s see how we can build the rest of the screen to match our design specs using the Compose toolkit.
You can watch the accompanying video to this article here:
Jetpack Compose makes it easy to give your app a consistent look and feel by shipping with an implementation of material design from the start. Material design is an adaptable system of guidelines, components, and tools that support the best practices of user interface design.
Jetpack Compose supports Material Design 2 and 3. Material 3 is the next evolution of Material design featuring updated components and “Material You” customization features designed to match the new visual look and feel on Android 12 and above. With Material Design, your app can be themed to match your brand by providing custom colors, typography, and shapes all in one place.
Jetsurvey uses material theming to style the whole app. The Theme.kt file defines a composable function called
JetsurveyTheme which uses the
MaterialTheme composable function to provide custom values for colors, shapes, and typography.
To ensure that the color scheme of the app responds automatically when the system theme is changed by the user, different colors are used in the theme, depending on the system appearance: light or dark.
Custom fonts and styles like weight, size, and line height are set in the Typography.kt file. To style text, callers can reference the typography property of
MaterialTheme.typography.titleMedium), rather than defining text styles at the call site, which allows text to appear and be styled consistently.
Custom shapes are also configured in Shape.kt to allow customization of rounded corners for different sizes of shapes in the app.
To learn more about theming, check out Material Theming in Compose.
Scaffold is a fundamental Material Design component that is part of the toolkit. It is a basic layout for arranging Material components in common screen patterns, such as a screen with a
The above snippet will render a screen containing a top app bar, a floating action button, and an area to display content (currently displaying an empty area).
Does this look familiar? The survey screen from Jetsurvey also conforms to
If you want to see how this is implemented, check out the
SurveyQuestionsScreen composable function in the SurveyScreen.kt file.
While having a top/bottom app bar and floating action button are common uses for
Scaffold, it supports other configurations as well such as hosting a Navigation drawer or
Scackbar. To learn more, check out the Scaffold reference docs.
Surface and more components
Another fundamental component in Material Design is the concept of a
Surface is a central metaphor in Material Design which content sits on. Surfaces can wrap your composables so that you can customize their background color, shape, border, as well as tonal and shadow elevation.
Surface, chances are you’re going to need a lot more components to build any kind of UI you can think of. This is why Compose provides a bunch of other Material Design components out-of-the-box like:
- Top and bottom app bars
- Floating action buttons
- …and a whole lot more
Understanding and building in ways that cater to the diverse needs of your users can be a challenge. To help with this, Material 3 components are also all accessible by default, featuring acceptable color contrast ratios, a minimum touch size, and more.
We’ve looked at how to arrange components on a single answer in the survey by using the
Row composable function. But how do we arrange all the different components for the rest of the screen? We do that by using layouts!
Compose has 3 standard layout elements. As we’ve seen previously, to horizontally arrange items, we can wrap our UI components in a
Row composable function. To vertically arrange items, we can use the
Column composable function. On the other hand, if we wanted to put or stack elements on top of another, we could use the
These standard layouts also accept parameters so you can further control how items are placed. Taking the implementation we saw previously of
Row without configuring it), if we try to run this, an answer in the survey would actually look something like this:
To change that, let’s pass in some additional parameters to the
Row composable function.
The vertical alignment of items in the
Row can be changed via the
verticalAlignment parameter. Since we want items to be centered vertically, let’s pass
Alignment.CenterVertically as its value. Furthermore, we’ll also want to change the horizontal arrangement of items so that they are spaced evenly across the
Row without free space before the
Image and the
Arrangement.SpaceBetween as the value. We won’t see much of an effect yet with this change, but we’ll see why this matters in a bit.
Our code should now look something like this:
…and the resulting UI:
There’s so much more to layouts so make sure to check out the documentation pages about layouts to learn more.
So far, we’ve covered styling, components, and layouts. But how do we control things like sizes, padding, and other appearances?
You do that by using modifiers! Modifiers allow you to decorate or augment a composable. Every composable function in the compose toolkit accepts a
Modifier as a parameter. Modifiers can be chained together until you achieve your desired customization.
Modifiers allow you to do all sorts of things like set a background color, change the size, add padding, change the alpha of the element, and even process click inputs from the user.
Additional modifiers might also be available to you depending on the scope of a composable function.
For instance, if you are within the scope of a
align modifier allows you to position an element relative to the containing
Box. The code snippet below shows changing the alignment of the
Text element to be
BottomEnd so that it aligns to the bottom right corner of the
Box. This modifier wouldn’t be accessible outside of the
Box composable and its scope, making modifiers type safe.
Updating SurveyAnswer with Modifiers
Using modifiers, we can further customize the
SurveyAnswer composable to match our designs. Let’s also assume here that this composable is called within our app’s theme so that the typography, shapes, and colors match our brand.
First, let’s further customize the
Row by passing in a
Modifier. Since we want the item to occupy the maximum allotted horizontal space, let’s call
fillMaxWidth. Also, since we want 16 dp of padding around the container, let’s chain a
padding modifier as well.
With these modifications, our survey answer is looking a lot closer to our desired output. Notice that the
Text’s width occupies the available space between the
RadioButton thanks to the
Arrangement.SpaceBetween value we passed in for the
horizontalArrangement value for the
To add a border and adjust the corners of the answer we’ll need to wrap the
Row around a
Surface composable. Doing so, we can configure the shape, border color and stroke size. With the following changes, we should now see the answer match our desired output.
We covered a lot! In the article, we were able to build a simple screen using Material theme and the Material components provided out of the box. We also saw how we can lay out composables using
Box, and how to build that pixel perfect UI with modifiers.
In the next article, we’ll cover Compose tooling and show how these tools can help accelerate your development.
Got any questions? Leave a comment below or use the #MADCompose hashtag on Twitter and we will address your questions in our upcoming live Q&A for the series on October 13. Stay tuned!