Bye XML, it was nice knowing you (pt. 1)

Filip Wiesner
Apr 9 · 7 min read

This article will focus on the basics of Compose and example of implementation of specific UI design (just looks — no state management nor architecture).
Not everything is explicitly defined for a reason. You should follow along with your own code and not just copy mine :)
If you really don’t want to code along or are just stuck,
here is the full project.
Part 2
here and part 3 here.

I’ve always struggled a bit when implementing a complex UI hierarchy with XML. Not really because it’s slow or hard to make, but because it feels like a black box that you need to fight again and again to make it behave just the way you want it to. Of course, it’s not really a black box because you can inspect the code and see exactly what is happening, but you’re not really encouraged to with components like TextView.java having 13 705 lines of code and the elephant in the room View.java with 30 407 lines of code (at the time of writing).

View.java
View.java — Android source code

Another problem is that it’s impossible to do everything from the XML and still have to manage it from the Kotlin or Java code. So we end up jumping from XML to Kotlin, not really knowing how the UI will end up behaving. And in the end, the XML is only the initial state of the UI, and we have to manage every change. Data binding can partly fix this but mixing XML and Java code in one file only makes it worse, in my opinion.

I am not saying anything groundbreaking here. Every Android developer knows this and especially the Android developers who made the framework. That’s why they came up with something better. A modern UI toolkit that solves all of the old one's problems while (and more importantly) not introducing that many more.

It’s really that simple

I have some experience with declarative UI frameworks (e.g., React JS). When I heard about Jetpack Compose, I thought that if it’s at least the same experience, I’ll be happy but Compose really surprised me, Compose delivered life improvements in spades.
I love the trend where Kotlin frameworks try to simplify complex systems to be just as easy to write as regular code. Kotlin Coroutines broke the stigma that writing concurrent code is hard, and now Jetpack Compose is doing the same with UI. And it’s not just Android UI! The JetBrains team is making Compose Desktop, and there was even a working prototype of Compose for the web.

OK, but enough introductions. Let’s see really how easy it is to write UI with Compose with obligatory “Hello World” example:

// Activity::onCreate
setContent
{
Text("Hello World!")
}

And that’s it! No layout inflating, no XML file, and no need for instantiating 30k LOC long classes.
But it does not get that much more complex. Let’s turn it into a list of items:

Column {
repeat(100) {
Text("Item $it")
}
}

You don’t need adapters, and you don’t need to set any LayoutManagers and handle state change. All you need to do is to declare what you want, and Compose will handle the rest. If state changes, Compose runtime will refresh the UI by re-invoking our functions.
If we wanted the list to be lazy evaluated (equivalent to RecyclerView), we would just swap the Column for LazyColumn and repeat(100) for items(100) and that’s it.

The basics
Let’s go over the basics of what is Composable component and how to make one.

@Composable
fun MyComponent(name: String) {}

This is a declaration of a regular Kotlin function with @Composable annotation. The annotation marks the function for Compose compiler plugin, and we don’t really need to know the details of what it does under the hood. “It will sprinkle some magic onto it” will suffice. What is important to know is that Composable functions can only be called from other Composable functions (so it’s the same as suspend functions in that regard), and the @Composable annotation enables the function to remember the previous invocation (the keyword being remember so keep on that one, you will need it later)

If you want to know more about how the compiler works and how it transforms Composable functions, I highly recommend this video by Leland Richardson from KotlinConf 2019

Another important thing to mention before we put our hands on Compose is that Composable functions should be pure. That basically means that for each input (parameters of the function), there should be only one result, or in other words, if I call the same function with the same parameters multiple times, the resulting UI should be identical. This needs to be true because the Compose runtime can call our functions whenever it “feels” like (this is called recomposition), and we can never depend on some given “call behavior”.

Learn by example

OK, let’s dive into the code…finally :)
The best way to learn things is to try them out, so let’s take proper UI design and implement it using Jetpack Compose. I’ve chosen this design on Dribble because it has most of the things you need in a basic app screen: text, button, list, images, and some custom component (bell with notification dot).

Design by Aris Rahmat Fatoni

Divide and conquer
One of the first things you should do is to divide the design into components and each component into smaller components, and so on…
I’ve decided on 4 main pieces:
1. Header
2. Search
3. HouseList
4. PopularHouse
but you can structure it differently (or not at all, but I would advise against that)

Disclaimer:
I am only starting with Compose myself and have only ~100 hours of experience. If I say something inaccurate, be sure to let me know :)

@Composable Header()

The first part of the design will be the header with location selection and the notification bell.

Let’s further divide this into another three components: LocationSelector, Location and NotificationButton.

The first component will be the LocationSelector and it won’t actually select anything (we are just making the looks). So if we look at the picture, we can see that all we need is some text and an “expand” arrow icon. In the view system, we would probably create some XML file with LinearLayout with TextView and ImageView inside. In Compose it’s similar but instead of LinearLayout we will use Row component, instead of TextView we will use Text and instead of ImageView we will use Icon component.
We might end up with something like this:

If we call this function, we will indeed get the text “Location” with the icon next to it, but it does not really look like our design. The text looks fine, maybe it could be a little bit bigger, but most importantly, the icon has the wrong color and is slightly smaller. The color change is a fairly simple task because theIcon function takes tint parameter, but what about the size? OK, for this, we should sidetrack a little bit.

The Modifier
In the view-based system, we had attributes like layout_width or background inherited from View (or other class) but when components are functions, it would be really inconvenient to declare parameters for each attribute. That’s why we have Modifiers (and they are pretty awesome!).

The way we use Modifiers is by chaining and passing them to components we want to modify, which will most likely pass them along and until they reach (most likely) Layout component where the Modifiers will be materialized (executed). By “chaining” I mean adding more modifiers to an existing one or starting with Modifier object: Modifier.height(10.dp).width(50.dp). If we add this modifier to our icon, it will be 10 dp high and 50 dp wide.
Using Modifiers, we can extend components with almost anything. Some examples of modifiers are: clickable, padding, aspectRatio, offset, background and much, much more.
(We will create our own custom modifier in the following article)

Back to UI
Now when we know what is Modifier, we can make the drop-down icon bigger by using the size modifier, add a CenterVertically alignment to our Row and add space between Text and Icon with Spacer component and BOOM! our LocationSelector component is done.

Summary

In this part, we’ve learned what is Composable function, how do we write one, how to use basic layouts like Row and Column and what is Modifier.
We will learn about Material theme, writing custom Modifiers, and managing state in the next part.

MateeDevs

Prague software company

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store