From View to Composable: A Quick jump to Jetpack Compose from an Android View mindset (with cheat sheet)

Alex Styl
5 min readApr 4, 2022

--

From View to Composable: A Quick jump to Jetpack Compose from an Android View mindset (with cheat sheet)

Building User Interfaces (UIs) using Jetpack Compose can be daunting after years of building interfaces with Android Views (XML anyone?). This article covers the basics of Jetpack Compose from an Android View background in order to speed up your learning of Compose.

From View to @Composable

In Jetpack Compose, each component that needs to be rendered on the screen can be defined as a Kotlin Unit function marked with the @Composable annotation like this:

We call those functions composables. The above composable will render a Card with a title and a subtitle, with a spacing of 10.dp in between.

Every time the title and description change, the UI will be updated to reflect the updated values. This is what we call recomposition.

You may only call composable functions from other composable functions. Because of this, activities that use Composable to render their layouts will look like this:

setContent {} is an extension function of the ComponentActivity [1]. Using composables in a Fragment needs a ComposeView like so:

Set listeners and other common attributes using Modifiers

In the View world, there are some common attributes and features found in most Views out there. Things like setting click and touch listeners, applying elevation, alpha, to name a few. For anyone creating their own custom views, there was a lot of boilerplate code to implement for your view to support such operations.

Compose introduces the concept of Modifiers. Modifiers provide functionality and features to composables without being tied to specific composables. Some Modifiers can be used for styling the composable (see background(), border() , clip() , shadow(), alpha(), animateContentSize()), others help with the placement and sizing of the composable (see fillMaxWidth() , size(), heightIn(), padding()) and others can bring functionality to the composable such as enabling click behavior or dragging (see clickable() , draggable(), toggleable(), swipeable() ).

From ViewGroups to Rows, Columns and Boxes

There are some composables whose main purpose is to help you arrange other composables on the screen. Those composables are the ViewGroups of the Compose world.

The most common ones to get started are: Column , Row , Box , LazyColumn and LazyRow. These composables accept the composables they need to arrange withint a content lambda function. Some tend to provide a special Scope class receiver that enables access to specific Modifiers.

Instead of using a LinearLayout with a VERTICAL or HORIZONTAL orientation, use a Column or Row to arrange their composables vertically or horizontally respectively. Within their respective scope, you have access to the weight() modifier, which works the same way as a LinearLayout’s weight.

Row { Text(“Main Header”) Spacer(Modifier.weight(1f) Text(“23 mins ago”) }
Copy paste code @ https://gist.github.com/alexstyl/3b0780a927938b8079595a2983abb848

Instead of using a FrameLayout , use a Box in order to place composables on top of each other. In the Box’s Scope you have access to align which provides similar functionality to FrameLayout’s gravity.

Copy paste code @ https://gist.github.com/alexstyl/3b0780a927938b8079595a2983abb848

Working with lists is straightforward in Compose. Instead of using a RecyclerView with an adapter and view holders, use a LazyColumn or LazyRow to create a vertically or horizontally scrolling list respectivelly. The LazyListScope grants you access to the item {} function, in which you can place the items of the list without having to specify a ViewType anymore. As a bonus, there is a stickyHeader {} function which will provide sticky header functionality to the item.

Copy paste code @ https://gist.github.com/alexstyl/3b0780a927938b8079595a2983abb848

Wiring business logic in your Screen level composables

Even though all composables are pure Kotlin functions, you will quickly realise that some are different than others. A composable might represent an element on the screen (such as a contact photo) and others might represent an entire screen. The screen level composable (the top level one) is the place where you want to be holding objects such as your ViewModels, and pass down values emitted from the ViewModel to nested composables, while reacting to events emitted from its nested composables.

Having a composable receive the values it needs to render on the screen as parameters, while bubbling up any events such as click listeners is what we call state hoisting. It makes the composable stateless and enables reusability and flexibility. As an added bonus, any business logic wiring ends up living in a single composable instead of being scattered around.

Recap

This was a quick jump into Jetpack Compose coming from an Android View background. In the Compose world, each component that needs to be rendered on the screen is marked @Composable called a composable.

Use Modifiers to apply common functionality to any composable such as click listeners and elevation.

Composables such as Column , Row , Box,LazyColumn and LazyRow are the ViewGroups of the Compose world and can be used to arrange your composables on the screen.

Keep your composables stateless and do the wiring in the screen level composable to enable reusability and flexibility.

⚡️ BONUS⚡ Views to Compose Cheat Sheet

Here is everything covered in a glimpsable cheat sheet:

PS: I am active on Twitter. Follow @alexstyl for more Jetpack Compose tips.

Special thanks to Sebastiano Poggi for proof reading this article.

[1] ComponentActivity is part of the androidx.activity:activity-compose dependency (link)

--

--

Alex Styl

Left my high paying job to help devs build brilliant apps at http://composables.co • 10 years of Android Development • ex-Apple