DEV Community

Cover image for How to create realistic UI with Jetpack Compose
AKASH PATEL for MindInventory

Posted on

How to create realistic UI with Jetpack Compose

Jetpack compose is the new way to build UI for your android applications in a declarative manner. Now no more XML needed and you can build Android apps without construct the XML layout code.

Is it really possible to make UI design without XML??
Yes… You can do it with latest Jetpack Compose modern UI toolkit to make this thing possible. Using Compose, you can build your user interface by defining a set of composable functions that take in data and emit UI elements.


Key points of declarative UI pattern of Jetpack compose:

  • Accelerate development: It is fully compatible with your existing code.
  • Less Code: It does more with less code and avoids entire classes of bugs, so code is simple and easy to maintain.
  • Powerful Tools: You can create attractive apps with access to the Android platform APIs.
  • Intuitive: You just need to describe your UI and then Compose will take care of the rest. Every time the state changes, the UI automatically gets updated.

In this Article, we will create UI of Flower app from our Dribbble shots and will learn how to create simple UI with Jetpack Compose.

Mindinventory

So without wasting your time let’s begin.

Quick Start
To get started with Jetpack Compose, a couple of Gradle dependencies need to be imported.

//App level build.gradle
implementation("androidx.compose.ui:ui:1.0.5")
// Tooling support (Previews, etc.)
implementation("androidx.compose.ui:ui-tooling:1.0.5")
// Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
implementation("androidx.compose.foundation:foundation:1.0.5")
// Material Design
implementation("androidx.compose.material:material:1.0.5")
// Material design icons
implementation("androidx.compose.material:material-icons-core:1.0.5")
implementation("androidx.compose.material:material-icons-extended:1.0.5")
Enter fullscreen mode Exit fullscreen mode

Also need to add the compose flag as true, in the buildFeatures block within android:

//App level build.gradle
buildFeatures {
    compose true
}
Enter fullscreen mode Exit fullscreen mode

The entry point to a Compose app
As Jetpack Compose exposes a programmatic way to build user interfaces, you won’t be using any XML. Instead of calling setContentView(R.layout.activity_main) you have to construct the setContent method.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            Text("Hello, World!")
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Let’s create a flower list and showing basic information

If we need to design the UI with more elements, then will go with Linear layout, Relative layout or Constraint layouts to get the perfect design.

To achieve the same in Jetpack compose we have to use some specific containers. For example, Column is the one of the container.

Column { 
    //Write your design here
}
Enter fullscreen mode Exit fullscreen mode

As the name of the function describes, this will align the elements in the vertical order. Here we have an example with two Text widget with some values in vertical order.

@Composable
fun FlowerCard(flower: Flowers){
    Column {
        Text(
            text = flower.name,
            style = TextStyle(
                color = gray,
                fontSize = 16.sp
            )
        )
        Text(
            text = flower.price,
            style = TextStyle(
                color = colorPrimary,
                fontSize = 16.sp
            )
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

Now, let’s take add item button to Right of flower info.

As you might expect, you can use the Row() function which lets you stack elements horizontally. The default settings stack all the children directly next to each other, with no spacing.

@Composable
private fun FlowerCard(flower: Flowers) {
    Row(modifier = Modifier.padding(20.dp)) {
        Column(modifier = Modifier.weight(1f)) {
            Text(
                text = flower.name,
                style = TextStyle(
                    color = gray,
                    fontSize = 16.sp
                )
            )
            Text(
                text = flower.price,
                style = TextStyle(
                    color = colorPrimary,
                    fontSize = 16.sp
                )
            )
        }
        IconButton(
            onClick = { },
            modifier = Modifier.background(
                color = colorPrimary,
                shape = RoundedCornerShape(10.dp)
            )
        ) {
            Icon(Icons.Default.Add, tint = Color.White,  contentDescription = null)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

With the code above, we used modifier to add some padding. But, what exactly is a modifier? A modifier is an ordered, immutable collection of elements that decorate or add behavior to Compose UI elements like backgrounds, padding, click event listeners, and many more.

Now, let’s wrap this row with a Card.

@Composable
private fun FlowerCard(flower: Flowers) {
    Card(
        shape = RoundedCornerShape(14.dp),
        backgroundColor = Color.White,
        modifier = Modifier.padding(10.dp).width(180.dp)
    ) {
        Row(modifier = Modifier.padding(20.dp)) {
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = flower.name,
                    style = TextStyle(
                        color = gray,
                        fontSize = 16.sp
                    )
                )
                Text(
                    text = flower.price,
                    style = TextStyle(
                        color = colorPrimary,
                        fontSize = 16.sp
                    )
                )
            }
            IconButton(
                onClick = { },
                modifier = Modifier.background(
                    color = colorPrimary,
                    shape = RoundedCornerShape(10.dp)
                )
            ) {
                Icon(Icons.Default.Add, tint = Color.White,  contentDescription = null)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Card has a lot of attributes that you can use. To have a rounded shape (or any other shape), you can use the shape attribute. Using modifier you can give padding, width and height for the card. Card accept one child under it to show information.

Your Card will look like this.

Now, want to add Image of flower above the flower information. Mean, you want to show multiple information on the card, but as we know, Card accepts only one child. Thus you have to use the Column.

@Composable
private fun FlowerCard(flower: Flowers) {
    Card(
        shape = RoundedCornerShape(14.dp),
        backgroundColor = Color.White,
        modifier = Modifier.padding(10.dp).width(180.dp)
    ) {
        Column(
            modifier = Modifier.fillMaxWidth().padding(10.dp),
        ) {
            Image(
                painter = painterResource(id = flower.image),
                contentDescription = null,
                modifier = Modifier.size(140.dp),
            )
            Row(modifier = Modifier.padding(top = 20.dp)) {
                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = flower.name,
                        style = TextStyle(
                            color = gray,
                            fontSize = 16.sp
                        )
                    )
                    Text(
                        text = flower.price,
                        style = TextStyle(
                            color = colorPrimary,
                            fontSize = 16.sp
                        )
                    )
                }
                IconButton(
                    onClick = { },
                    modifier = Modifier.background(
                        color = colorPrimary,
                        shape = RoundedCornerShape(10.dp)
                    )
                ) {
                    Icon(Icons.Default.Add, tint = Color.White,  contentDescription = null)
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In the above code, to add an image we used the Composable function Image.

Image(
    modifier = Modifier.size(140.dp),
    bitmap = imageResource(id = flower.image)
)
Enter fullscreen mode Exit fullscreen mode

In earlier compose versions before 1.0.0-alpha12, imageResource was used for loading drawable in Image same as above.

Now, with 1.0.x you can use the painterResourcefunction to load vector drawables. You don't need to know the type of the drawable, simply use painterResource in Image composables or paint modifiers.

This method can load either an instance of BitmapPainter or VectorPainter for ImageBitmap based assets or vector based assets respectively.

Image also has a lot more properties for scaling, aligning, and changing the UI representation of the image.

Creating a List of flowers.

Normally, to make a list you’d use something like a RecyclerView. Similar to it, a LazyRow is used in Jetpack Compose. It is a horizontal scrolling list that only composes and lays out the currently visible items.

Now putting all together, creating PopularFlowersList().

From Version 1.0.0-alpha09 LazyColumnFor, LazyRowFor, LazyColumnForIndexed and LazyRowForIndexed are deprecated. Use LazyColumn and LazyRow instead of it.

@Composable
private fun PopularFlowersList() {
    LazyRow {
        items(items = FlowersData.list, itemContent = { flowers ->
            FlowerCard(flowers)
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

Image description


Congratulations!!! You’ve built your first real world UI using Jetpack Compose.

Click here to see an example.

Stay tune know more about Jetpack compose and coding pattern & architecture and by the time keep composing!!

Top comments (0)