ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

A Brief Overview of Jetpack Compose

This article is for the 5th day of the UniFa developer blog Advent Calendar 2021.

adventar.org

Hello, this is Shakil from Product Engineering Department.

In this blog I am going to talk about the very basics of Jetpack Compose and why it is a good alternative to UI creation compared to traditional XML.

Jetpack Compose is Android’s modern toolkit for building native UI and is to replace XML in the future. It allows for really fast and simplified UI development with a lot less code by means of declarative functions a.k.a Composables.

I am not going to talk about how to integrate Compose to your project now but if you would like to know how, you could go here.

What is Declarative UI

Declarative UI is a design paradigm that allows developers to design the user interface based on data received and makes use of one programming language to create an entire application.

Examples of such frameworks include Flutter, React native, SwiftUI and Jetpack compose.

Why use Jetpack Compose?

  • We can directly create UI in Kotlin, along with all the business logic. No XML required.
  • With Compose, we can achieve same results as XML with lesser lines of code. Hence lesser to test, maintain and understand.
  • Very easy to create different kinds of animations.
  • It significantly reduces the app size because we have to write lesser code.
  • Single source of truth for UI states.
  • For more you can read this.

Creating UI with Compose

In the traditional Android development, we used to use different kinds of Layouts like  RelativeLayout, LinearLayout, FrameLayout, ConstraintLayout, etc for creating UI elements each with their own perks and complexities. Jetpack Compose right now offers a much simpler way to to create UI with simple elements like:

  • Row
  • Column
  • Box

Compose also has support for ConstraintLayout, but implementing it is not trivial and does not offer greater simplicity compared to XML. However, it is quite unlikely that we will need it when working with Compose as the three elements mentioned above works just as well if not better when creating any type of UI.

Row and Column

Row as its' name suggests is used to place components horizontally on the screen. Similarly, Column is used to place components vertically on the screen. Column & Row are Composable inline functions with arguments: Modifier, horizontalArrangement, verticalAlignment, and content. Except content, all the other arguments are optional. Let’s a look at the Row and Column integrated together below:

@Composable
fun ColumnRowExample(){
    Column(
        modifier = Modifier
            .fillMaxWidth() // Takes up max with it can inside its' parent
            .background(Color.White), // Color class here is different from COLOR class we are used to
    ) {

        Row(
            modifier = Modifier.fillMaxWidth().background(Color.Magenta),
        ) {
            Text(
                text = "無駄。無駄。無駄。。。。",
                style = MaterialTheme.typography.h6,
                textAlign = TextAlign.Left,
                modifier = Modifier.weight(2f).padding(16.dp)
            )
            Text(
                text = "DIO",
                style = MaterialTheme.typography.h6,
                textAlign = TextAlign.Right,
                modifier = Modifier.weight(1f).padding(16.dp)
            )
        }

        Row(
            modifier = Modifier.fillMaxWidth().background(Color.LightGray),
        ) {
            Text(
                text = "おら。おら。おら。。。。",
                style = MaterialTheme.typography.h6,
                textAlign = TextAlign.Left,
                modifier = Modifier.weight(2f).padding(16.dp)
            )
            Text(
                text = "承太郎",
                style = MaterialTheme.typography.h6,
                textAlign = TextAlign.Right,
                modifier = Modifier.weight(1f).padding(16.dp)
            )
        }
    }
}

The output looks like the following:

f:id:unifa_tech:20211203121856p:plain
Example Rows and Columns

Box

Box is kind of similar to RelativeLayout. Children in the Box will be stacked on top of one another unless we use an alignment modifier to specify where the composable should be drawn. Following shows an example:

@Composable
fun BoxExample(){
    Box(
        modifier = Modifier.fillMaxWidth()
            .background(Color.Yellow),
    ) {
        Text(
            text = "夢があります。",
            style = MaterialTheme.typography.h6,
            modifier = Modifier.align(Alignment.TopStart).padding(16.dp)
        )

        Text(
            text = "MLK",
            style = MaterialTheme.typography.h6,
            modifier = Modifier.align(Alignment.TopEnd).padding(16.dp)
        )
    }
}

The output looks like the following:

f:id:unifa_tech:20211203122240p:plain
Example Box

Although this was just a brief overview, we can basically create almost any kind of UI using a combination of just the Rows, Columns and Boxes and using the Modifier argument to change their look and feel.

Modifiers

This object is used to define properties for our composable and makes use of the builder pattern. This means that changes are applied in the order of which they were set in the modifier object.

How about Displaying Long Lists

Currently in order to display long lists we use RecyclerView and have to create UI for each element in the list in a separate XML file and need to create Adapters and what not. In short displaying long list currently can be quite cumbersome involving multiple file and a lot of lines of code. Compose greatly simplifies this with LazyColumn & LazyRow.

Following shows an Example:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // We should never create and populate lists in Activity or Fragment
    // However I am just using this as an example, so should be Ok :D
    val list = mutableListOf<String>()
    for (i in 1..500) {
        list.add("This is item $i")
    }
    setContent {
        LazyColumnExample(list.toList())
    }
}

@Composable
private fun LazyColumnExample(list: List<String>) {
    LazyColumn {
        itemsIndexed(list) { _, content ->
            Text(
                text = content,
                fontSize = 32.sp,
                fontWeight = FontWeight.Bold,
                textAlign = TextAlign.Left,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 14.dp)
            )
        }
    }
}

The output looks like the following:

f:id:unifa_tech:20211203122314p:plain
Example Displaying Long Lists

Wasn't that really simple. We no longer have to deal with Adapters (Yay! 😁 ). While the example above used a Text Composable for simplicity, we can definitely use our own custom composable as well.

Conclusion

This was just a brief overview of Compose. Hope you found it somewhat helpful. If I can, I would like to write more about Compose in the future regarding States, Animation, Pagination, Navigation, etc.

unifa-e.com