Intro to Jetpack Compose

TribalScale Inc.
TribalScale
Published in
7 min readMar 7, 2022

Written by: Sehrish Shoaib, Agile Software Engineer, TribalScale

📫 Subscribe to receive our content here.

💬 Have any questions about Jetpack compose? Click here to chat with one of our experts!

Photo by Christopher Gower on Unsplash

The User Interface (UI) has always been the essence of any product. In an Android mobile application, the importance of UI design and interaction is of great value in building an amazing application that appeals to a greater user base.

Jetpack Compose is Google’s new modern toolkit for writing UI. It is an evolutionary next step in Android development and allows us to create beautiful UIs in much less code than before. Furthermore it is intuitive, powerful and declarative.

Being an Android developer, there has always been two parts to developing an Android application. First, the UI which was developed in XML layouts using View hierarchies, and secondly, the logic behind the UI including databinding, databases, network calls etc. Jetpack Compose is all about the UI and implementation of the design layer in an Android app, while simultaneously simplifying the communication with the logic side of the app.

One of the basic features of Jetpack Compose is that it is written in Kotlin which eventually allows developers to write an Android app completely in one language and eliminates the need for XML layouts. The advantages of moving to Kotlin are many. Using the same language base allows developers to easily follow the principle of separation of concerns. A declarative programming style is introduced in Compose which has shifted the focus of how a program works to what the program intends to accomplish. This makes converting logic to code much more intuitive. Recomposition is also introduced which is one of the most important benefits of Compose, by which any composable function can be re-invoked so that when the state of UI changes, all the composables, depending on that state, will recompose and update the UI.

Defining a composable function

In Jetpack Compose we use composable functions to create the UI. These are like regular functions in which parameters can be passed and returned. The following is a snapshot of a simple compose function annotated with @Composable and then @Preview which as the name suggests, allows us to see the UI while writing code.

@Composable
fun LandingPage(title: String) {
Text(text = "$title")
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
MyApplicationTheme {
LandingPage("Tribalscale Blogs")
}
}

Structuring your UI components using layout composables & adding elements

Scaffold implements the basic material design visual layout structure. This component provides an API to put together several material components to construct your screen, by ensuring proper layout strategy for components and collecting necessary data so they work together correctly.

Let’s implement a simple screen in Jetpack Compose to understand its ease and efficiency. A simple example of a Scaffold with TopAppBar, FloatingActionButton and Content will be explored as shown in the figure below.

Our screen in Jetpack Compose

For the topBar we can simply define backgroundColor and title along with a navigationIcon to open a navigation drawer. This is implemented in the code shown below:

@Composable
fun LandingPage() {

Scaffold(
modifier = Modifier.fillMaxHeight(),

topBar = {
TopAppBar(
backgroundColor = MaterialTheme.colors.background,
title = { Text("Title") },
navigationIcon = {
IconButton(onClick = { /* Open Nav drawer */ }) {
Icon(Icons.Filled.Menu, contentDescription = null)
}
},

Then in actions two action buttons are being defined, one with a default Search icon and other with custom image using painterResource.

actions = { 
IconButton(onClick = { /* Navigate to Search fragment */ }) {
Icon (Icons.Filled.Search, contentDescription = null)
}
IconButton(onClick = { /* Navigate to About fragment */ }) {
Image(
painter = painterResource(R.drawable.tribalscale),
"icon description"
)
}
}

The floating action button can be one of two types—one with an icon or one with extended FAB that contains text and an optional icon.

floatingActionButtonPosition = FabPosition.End,
floatingActionButton = {
FloatingActionButton(onClick = { /* fab click handler */ }) {
Icon(Icons.Filled.Notifications, contentDescription = "fab description")
}
}

Now coming to the Content. We will now define the layout in terms of Column which will allow us to create our layout in a vertically arranged format. We can consider it as a stack but the way its elements will be defined top down. It’s important to remember as you write the code that the order of components will be defined in the same way as they are placed in code. So if we visualize a stack being written starting from the top element first, in our example we have a Text placer for the title and then a Box element which we can repeat. Spacer allows us to add padding in vertical or horizontal format. The code is shown below:

content = {
Column(
modifier = Modifier
.fillMaxWidth()
) { Text(
text = "Tribalscale Blogs",
color = colors.secondary,
style = MaterialTheme.typography.h2 )

Spacer(Modifier.padding(vertical = 10.dp))

The added advantage of composables is that we can define separate composables for different parts of our screen and reuse them just like any other function by passing different parameter values in order to change their contents. We can even use them in different Android projects.

Adding animation

Let’s add some animation so that the background color of the box will change once the user clicks it, along with making it possible to expand its contents.

Jetpack Compose gives us functions remember and mutableStateOf to keep track of whether or not the text has been enlarged. These functions allow us to keep track of this state change. See the code below:

var isExpanded by remember { mutableStateOf(false) }

val boxColor: Color by animateColorAsState(
if (isExpanded) Green else Yellow)

Composable functions can use remember to store local state in memory and track changes to the mutableStateOf value. When the value is modified, all composables that use this state will be automatically repainted. This is referred to as recomposition. Any changes to state are automatically updated in the UI when utilizing Compose’s state APIs like remember and mutableStateOf.

When we click on a message, we can now change the background of the message and its content based on isExpanded, as defined in the following lines of code:

maxLines = if (isExpanded) Int.MAX_VALUE else 2

To handle click events on the composable, we’ll utilize the clickable modifier. As a result, when clicked, our output screen will behave as shown in the figure below:

Screen with first box clicked and expanded

Using modifiers to extend composables

Last but not least are the Modifiers. They allow a developer to add various customizations to a composable like:

  • Alter appearance such as width, height, shape style and background colors to name a few.
  • Alter behavior like adding clickables or making content scrollable.

You can chain any number of modifiers as seen in code below.

Within the Box element and after defining the modifiers, we have structured the box within a Row that contains an Image and then a Column with two texts. As you can see, visualizing the elements and connecting them with the code is very simple and intuitive. The remaining part of the code including modifiers is as shown below:

Box(
Modifier
.padding(horizontal = 10.dp)
.width(360.dp)
.height(130.dp)
.clip(RoundedCornerShape(10.dp))
.background(boxColor)
.clickable { isExpanded = !isExpanded }

)
{ Row(
Modifier.fillMaxHeight(1f),
verticalAlignment = Alignment.CenterVertically
) {
Image(
modifier = Modifier
.padding(horizontal = 10.dp)
.size(100.dp)
.clip(RoundedCornerShape(10.dp)),
painter = painterResource(R.drawable.image_1),
contentDescription = "Image description"

)
Column(Modifier.padding(end = 5.dp)) {
Text(
text = "Product",
style = MaterialTheme.typography.h4
)
Text(modifier = Modifier.padding(all = 0.dp),
maxLines = if (isExpanded) Int.MAX_VALUE else 2,
text = "Product Blogs that give insight into innovative global products. \n - Blog 1 \n - Blog 2",
style = MaterialTheme.typography.body2,
)
}
}
}

Sehrish is an Agile Software Engineer at TribalScale working on innovative and futuristic Android apps. She has a Masters degree in Computer Engineering and is greatly passionate about working on the UI side of Android. She loves writing code and building innovative apps. Outside of work she is an avid reader who loves books and libraries!

TribalScale is a global innovation firm that helps enterprises adapt and thrive in the digital era. We transform teams and processes, build best-in-class digital products, and create disruptive startups. Learn more about us on our website. Connect with us on Twitter, LinkedIn & Facebook!

--

--

TribalScale Inc.
TribalScale

A digital innovation firm with a mission to right the future.