What is compose and Why we should use it?
Compose is a UI toolkit for android that follows a declarative pattern to build and manage UIs. When you’ve got complex layouts, handling all the widgets in the layout can be tricky sometimes, and that’s what Compose allows you to solve on top of simplifying the UI development process. While working with XML layouts, you have a hierarchy of views, and each time you want to update or initialize a view by using findViewById(), the app needs to traverse through the hierarchy, which is expensive. In complex layouts, when there’s a state change, you’ve to manually write the code to make sure that you update the related widgets when the state of the app changes. Using compose, you don’t have to worry about manually going through the code to ensure that you’re updating your views because Compose handles it for you. Besides, when there is a change in the app’s state, compose only regenerates the composables that rely on the state rather than regenerating the whole screen. This process is called Recomposition, and Composables are the functions you create to include your UI parts.
Before we start using Compose, you’d need the latest canary version of Android Studio. Once you install it, create a new project and select Empty Compose activity. Android Studio will automatically generate all the necessary files and dependencies for you to start developing with Compose. I got the idea of the design from here
Themes and Colors
By default, compose includes Material theme and components making it easier for you to use material components and design a theme for your application with colors, typography, and shape. The first thing that we will do is define colors that we’re going to use in the app. For the app that we’re going to design, we’ll only need the yellow color, and we’re going to define it in Color.kt, which is where you’ll define all the colors you want to use in the app. Color in Compose only accepts a parameter of type RGB, ARGB, ColorSpace, and colorInt when defining colors. So, we’ll parse the hex string color to colorInt and get the yellow color.
It is in Theme.kt file where you define all the themes for your app. We’ll only look into the LightColorPalette for now to add the yellow background for the app. LightColorPalette includes colors that the app will use when the system is not in dark theme. In the LightColorPalette, we’ll use the color yellow for the surface, and since we want the color contents on the surface to be black, we’ll define onSurface color to be black.
Building the UI
Now to build the UI, we’ll define a composable function called AppUI, which will hold all the app contents. We annotate composable functions with @Composable, and only composable functions can call other composable functions. Also notice that we declare composable functions outside of the activity class. AppUI accepts lambda as a parameter, a composable content that we want in the upper half of the screen. Since the composable functions don’t return anything, the type of the parameter is @Composable () -> Unit. If you look into the first line of code in the AppUI, you can see that we are calling Y_DesenharPortugalTheme, a theme that’s automatically generated for us and implements MaterialTheme, and you can see it in Theme.kt file. Depending on the name of the app, the name of the theme will be different.
Compose provides us with objects that we can use to build our app’s UI, and Surface is one of the objects. Surface accepts different parameters to define its attributes, but we only want the color and contentColor. Like Surface, Column is another compose object that allows us to place objects vertically. When you look at the app’s final design, you can see that all the elements are vertically laid out, which is why we’ll use Column. Modifiers allow us to change the behavior, appearance of the app. Modifier.fillMaxSize() uses the maximum size there is available for the contents to use. As we want to occupy the whole screen of the app, we’ll use the fillMaxSize(). We also have another modifier in the innermost Column, but this time we use the weight attribute and set it to 1 because the upper half contents occupy more space than the contents in the bottom half of the screen.
In the UpperHalf composable function, we define the UI components that we want in the top half of the screen. The first object is a line that occupies the full width of the screen. We can use a Divider to accomplish that, and we’ll also set the padding and maximum width in its modifier. We can chain the calls in the modifier. However, when you are chaining multiple calls in modifier, the order that you are chaining the calls matter, and the modifier uses left to right or top to bottom calls in the chain to apply to the composable object. For the Divider, the padding is applied first, and then the maximum width is applied. For the two small-sized texts that appear after the divider, we’ll use smallLetterStyle, which is an immutable variable that we’ve defined in the function. For the third text, however, we’ll center it horizontally and also apply typography style h3. Copy allows us to override default values, and since we want the text to be lighter than the default weight, we’ll set it to Light.
For the elements in the bottom half of the screen, we’ll use a Row object. Row is also a composable object like Column, Text, and Divider, and with it, we can place the contents horizontally, which is what we want to produce for the elements in the bottom half of the screen. Although all the items are horizontally placed on the screen, each piece has its own composition. The contents of each of the elements are in vertical order, which is why we’ll use Columns in every component to meet the design. If you look into the code for the last element of the row, notice how the modifier calls are chained for the last text element. If we were to change the order of the calls, the output would be different. Here the calls are made from top to the bottom of the chain.
After creating the composable functions, we’ll call AppUI from setContent in MainActivity and pass in the upper half composable function as the argument to the lambda. In the AppUI composable function, we’ll call the parameter in the innermost Column whose weight is set to 1, and we’ll call BottomHalf() outside of the Column. We also have a composable to preview the UI, PreviewApp. Composables annotated with @Preview on top of @Composable are parameterless functions.
Every time you want to preview the changes of the UI without running the emulator or installing it on your device, you can do so by creating a preview composable functions and building your project. The function will reflect your changes in the split and design tab.
Compose is still in alpha, but it already proves how efficient it can be in building layouts. This was a simple example of using Compose, where I wanted to express my understanding of a few UI objects that Compose offers and how we can utilize them to build the layout. You can also find the project at Github. I also found Thinking in Compose helpful to understand the material. Thanks for reading! If you have any questions, you can reach out to me on Twitter.