Open In App

Building UI Using Jetpack Compose in Android

Improve
Improve
Like Article
Like
Save
Share
Report

Jetpack Compose is a modern UI toolkit that is designed to simplify UI development in Android. It consists of a reactive programming model with conciseness and ease of Kotlin programming language. It is fully declarative so that you can describe your UI by calling some series of functions that will transform your data into a UI hierarchy. When the data changes or is updated then the framework automatically recalls these functions and updates the view for you.

Prerequisites:

  1. Familiar with Kotlin and OOP Concepts as well
  2. Basic understanding about Jetpack Compose
  3. Android Studio

So, we are just going to create an application UI using jetpack compose (Kotlin). our final UI will look like it.

It’s’ an easy UI to build using jetpack compose but a little bit hard using XML. So, let’s start step by step.

Step by Step Implementation

Step 1: Create a new android studio project

To create a new project in Android Studio using Jetpack Compose please refer to:- How to Create a New Project in Android Studio Canary Version with Jetpack Compose.

Step 2: Let’s Add resources to the project

There are some resources like colors, image assets, fonts, and some little things. You can easily find them otherwise just get them from the GitHub repo.

Step 3: Create a Kotlin class HomeScreen.kt

We can do the same task in MainActivity.kt as well, but it’s good practice to create another file. Initially, we start from the top, so creating the first header of the UI. having two texts with an image of a search icon. Things are very easy in this case we just create functions and call them, and that is how we can reuse the code very easily.

Kotlin




package com.cuid.geekscourse.ui.theme
 
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.cuid.composeui.R
 
// here we have created HomeScreen function
// and we will call all functions inside it.
// and finally just call this function from mainActivity
@Composable
fun HomeScreen() {
      // this is the most outer box that will
      // contain all the views,buttons,chips,etc.
    Box(
        modifier = Modifier
            .background(DeepBlue)
            .fillMaxSize()
    ) {
        Column {
              // this is how we call
              // function adding whole UI
            GreetingSection()
        }
 }
     
 
@Composable
 
// and this is the function
// just for creating header at top
fun GreetingSection(
    name: String = "Geeks"
) {
      // here we just arrange the views
    Row(
        horizontalArrangement = Arrangement.SpaceBetween,
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .fillMaxWidth()
            .padding(15.dp)
    ) {
        Column(
            verticalArrangement = Arrangement.Center
        ) {
              // heading text view
            Text(
                text = "Good morning, $name",
                style = MaterialTheme.typography.h1
            )
            Text(
                text = "We wish you have a good day!",
                style = MaterialTheme.typography.body1
            )
        }
        // search icon
        Icon(
            painter = painterResource(id = R.drawable.ic_search),
            contentDescription = "Search",
            tint = Color.White,
            modifier = Modifier.size(24.dp)
        )
    }
}


Step 4: Create another function for chips

As we have shown above in-app preview that we can change chips. So let’s build it.

Kotlin




// This is how we can create chip seaction at the top of app
 
@Composable
fun ChipSection(
     // function with single argument
    chips: List<String>
) {
    var selectedChipIndex by remember {
        // it will not update the string
        // but save and it will helpful for us
        mutableStateOf(0)
    }
    LazyRow {
        items(chips.size) {
            Box(
                contentAlignment = Alignment.Center,
                modifier = Modifier
                    .padding(start = 15.dp, top = 15.dp, bottom = 15.dp)
                    .clickable {
                        selectedChipIndex = it
                    }
                    .clip(RoundedCornerShape(10.dp))
                    .background(
                        // this is basic condition for selected chip index
                        if (selectedChipIndex == it) ButtonGreen
                        else DarkerButtonGreen
                    )
                    .padding(15.dp)
            ) {
                Text(text = chips[it], color = TextWhite)
            }
        }
    }
}


Step 5: Create a function for SuggestionSecation

It’s really a very basic part of this app. 

Kotlin




// This function is for suggestion secation
 
@Composable
fun SuggestionSection(
    color: Color = LightBlue
) {
    Row(   
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceBetween,
        modifier = Modifier
            .padding(15.dp)
            .clip(RoundedCornerShape(10.dp))
            .background(color)
            .padding(horizontal = 15.dp, vertical = 20.dp)
            .fillMaxWidth()
    ) {
        Column {
            // here are two text views or we can say only text
            Text(
                text = "Daily Coding",
                  // it can be litile bit confusing but
                  // it is just text style alternate
                  // of fontfamily in XML
                style = MaterialTheme.typography.h2
                   
            )
            Text(
                // same as above
                text = "do at least • 3-10 problems / day",
                style = MaterialTheme.typography.body1,
                color = TextWhite
            )
        }
        Box(
            // box containing icon
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .size(40.dp)
                .clip(CircleShape)
                .background(ButtonGreen)
                .padding(10.dp)
        ) {
            Icon(
                painter = painterResource(id = R.drawable.ic_play),
                contentDescription = "Play",
                tint = Color.White,
                modifier = Modifier.size(16.dp)
            )
        }
    }
}


The next step should be the card of courses but that is not easy or we can say the toughest part of the whole UI, so we will do it after the last one.

  • Let’s Create a BottomSection, but before that, we should create the class for simplicity
  • because our BottomSection element has two fields or views so let’s do

Step 6: Create Class for ButtomSection (BottomMenuContent.kt)

Kotlin




package com.cuid.geekscourses
 
import androidx.annotation.DrawableRes
// having two parameters title and iconid
data class BottomMenuContent(
    val title: String,
    @DrawableRes val iconId: Int
)


Step 7: Create function for ButtomSection 

Kotlin




@Composable
// this function tells us that
// how menu item should look like
fun BottomMenu(
    items: List<BottomMenuContent>,
    modifier: Modifier = Modifier,
    activeHighlightColor: Color = ButtonGreen,
    activeTextColor: Color = Color.White,
    inactiveTextColor: Color = AquaBlue,
    initialSelectedItemIndex: Int = 0
) {
    var selectedItemIndex by remember {       
        mutableStateOf(initialSelectedItemIndex)
    }
    Row(
        horizontalArrangement = Arrangement.SpaceAround,
        verticalAlignment = Alignment.CenterVertically,
        modifier = modifier   
            .fillMaxWidth()
            .background(DeepBlue)
            .padding(15.dp)
    ) {
          // it is basically what we should have
          // for creating an element of BottomMenuItem
        items.forEachIndexed { index, item ->
            BottomMenuItem(
                item = item,
                isSelected = index == selectedItemIndex,
                activeHighlightColor = activeHighlightColor,
                activeTextColor = activeTextColor,
                inactiveTextColor = inactiveTextColor
            ) {
                selectedItemIndex = index
            }
        }
    }
}
// it's basically how menu item should look like
@Composable
fun BottomMenuItem(
    item: BottomMenuContent,
    isSelected: Boolean = false,
    activeHighlightColor: Color = ButtonGreen,
    activeTextColor: Color = Color.White,
    inactiveTextColor: Color = AquaBlue,
    onItemClick: () -> Unit
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
        modifier = Modifier.clickable {
            onItemClick()
        }
    ) {
          // here are some peremetens
          // for how elements will align
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .clip(RoundedCornerShape(10.dp))
                .background(if (isSelected) activeHighlightColor else Color.Transparent)
                .padding(10.dp)
        ) {
            Icon(
                painter = painterResource(id = item.iconId),
                contentDescription = item.title,
                tint = if (isSelected) activeTextColor else inactiveTextColor,
                modifier = Modifier.size(20.dp)
            )
        }
        Text(
            text = item.title,
              // it's basic condition
            color = if(isSelected) activeTextColor else inactiveTextColor
        )
    }
}


Now, the final part of the app is a little bit tricky, which is nothing but the course item, this one:

course item

Here we have three colors, string and icon as well, then  same as above we will create a class, and set data during the function call

Step 8: Creating Class Course.kt

This section has five fields, so create five variables of their types. The fields you can see in the code as well.

Kotlin




package com.cuid.geekscourses
 
import androidx.annotation.DrawableRes
import androidx.compose.ui.graphics.Color
 
data class Course(
    val title: String,
    @DrawableRes val iconId: Int,
    val lightColor: Color,
    val mediumColor: Color,
    val darkColor: Color
)


Now just think about it, that how to make those curves on the card. So basically, we set some points and create a smooth curve by joining points created

Step 9: Creating CourseSection

It’s basically just how our grid will Arrange.

Kotlin




@ExperimentalFoundationApi
@Composable
// here we have just passed the list of courses
fun CourseSection(courses: List<Course>) {
    Column(modifier = Modifier.fillMaxWidth()) {
        Text(
            text = "courses",
            style = MaterialTheme.typography.h1,
            modifier = Modifier.padding(15.dp)
        )
        // we have used lazyVertically grid
        LazyVerticalGrid(
            cells = GridCells.Fixed(2), // it basically tells no. of cells in a row
            contentPadding = PaddingValues(start = 7.5.dp, end = 7.5.dp,bottom = 100.dp),
            modifier = Modifier.fillMaxHeight()
        ) {
            items(courses.size) {
              // here we have to define how one of these item is look like
              // we will tell after defining item design
              // let me comment it for now and after
              // creating you just have to remove
               
              // CourseItem(course = courses[it])
            }
        }
    }
}


Step 10: Creating Course Card Item Design

Kotlin




@Composable
fun CourseItem(
    course: Course
) {
    BoxWithConstraints(
          // Box with some attributes
        modifier = Modifier
            .padding(7.5.dp)
            .aspectRatio(1f)
            .clip(RoundedCornerShape(10.dp))
            .background(feature.darkColor)
    ) {
        val width = constraints.maxWidth
        val height = constraints.maxHeight
        // setting 5 points for medium
        // color or we can say for another
        // Medium colored path
        val mediumColoredPoint1 = Offset(0f, height * 0.3f)
        val mediumColoredPoint2 = Offset(width * 0.1f, height * 0.35f)
        val mediumColoredPoint3 = Offset(width * 0.4f, height * 0.05f)
        val mediumColoredPoint4 = Offset(width * 0.75f, height * 0.7f)
        val mediumColoredPoint5 = Offset(width * 1.4f, -height.toFloat())
        // joining points to make curves with the help of path class
        // path file that we have created earlier
        // having function that just help to reduce our code
        // and the function is standardQuadFromTo(m1,m2) taking
        // two peramente and connect them
        val mediumColoredPath = Path().apply {
            moveTo(mediumColoredPoint1.x, mediumColoredPoint1.y)
            standardQuadFromTo(mediumColoredPoint1, mediumColoredPoint2)
            standardQuadFromTo(mediumColoredPoint2, mediumColoredPoint3)
            standardQuadFromTo(mediumColoredPoint3, mediumColoredPoint4)
            standardQuadFromTo(mediumColoredPoint4, mediumColoredPoint5)
            lineTo(width.toFloat() + 100f, height.toFloat() + 100f)
            lineTo(-100f, height.toFloat() + 100f)
            close()
        }
        // it's another part of that
          // texture with light color
        // Light colored path
        val lightPoint1 = Offset(0f, height * 0.35f)
        val lightPoint2 = Offset(width * 0.1f, height * 0.4f)
        val lightPoint3 = Offset(width * 0.3f, height * 0.35f)
        val lightPoint4 = Offset(width * 0.65f, height.toFloat())
        val lightPoint5 = Offset(width * 1.4f, -height.toFloat() / 3f)
 
        val lightColoredPath = Path().apply {
            moveTo(lightPoint1.x, lightPoint1.y)
            standardQuadFromTo(lightPoint1, lightPoint2)
            standardQuadFromTo(lightPoint2, lightPoint3)
            standardQuadFromTo(lightPoint3, lightPoint4)
            standardQuadFromTo(lightPoint4, lightPoint5)
            lineTo(width.toFloat() + 100f, height.toFloat() + 100f)
            lineTo(-100f, height.toFloat() + 100f)
            close()
        }
        // canvas is used when we
          // want to draw something
        Canvas(
            modifier = Modifier
                .fillMaxSize()
        ) {
            drawPath(
                  // function for drawing paths
                  // just pass the path
                path = mediumColoredPath,
                color = course.mediumColor
            )
            drawPath( // it's for the lighter path
                path = lightColoredPath,
                color = course.lightColor
            )
        }
         // so , we have done with texture and
         // now just creating box and other things
        // box containing course elements
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(15.dp)
        ) {
            Text(
                text = course.title,
                style = MaterialTheme.typography.h2,
                lineHeight = 26.sp,
                modifier = Modifier.align(Alignment.TopStart)
            )
            Icon(
                painter = painterResource(id = course.iconId),
                contentDescription = course.title,
                tint = Color.White,
                modifier = Modifier.align(Alignment.BottomStart)
            )
            Text(
                text = "Start",
                color = TextWhite,
                fontSize = 14.sp,
                fontWeight = FontWeight.Bold,
                modifier = Modifier
                    .clickable {
                        // Handle the clicks
                    }
                    .align(Alignment.BottomEnd)
                    .clip(RoundedCornerShape(10.dp))
                    .background(ButtonGreen)
                    .padding(vertical = 6.dp, horizontal = 15.dp)
            )
        }
    }
}


That’s all about, how our item will look like. So just pass the item in the course section

CourseItem(course = courses[it])

It’s that file that we have discussed above to reduce our code

Kotlin




package com.cuid.geekscourses
 
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Path
import kotlin.math.abs
// The function is standardQuadFromTo(m1,m2)
// taking two peramente those are nothing but points
// that we are created and just add.
fun Path.standardQuadFromTo(from: Offset, to: Offset) {
      // this function is basically draw
      // a line to our second point and
      // also smooth on that line and make it curve
    quadraticBezierTo(
        from.x,
        from.y,
        abs(from.x + to.x) / 2f,
        abs(from.y + to.y) / 2f
    )
}


Now we have all the things ready so just call all the functions and see your result as 

Kotlin




@ExperimentalFoundationApi
@Composable
fun HomeScreen() {
    // this is the most outer box
      // having all the views inside it
    Box(
        modifier = Modifier
            .background(DeepBlue)
            .fillMaxSize()
    ) {
        Column {
              // this is the function for header
            GreetingSection()
            // it's for chipsSecation, and pass
              // as many strings as you want
            ChipSection(chips = listOf("Data structures", "Algorithms", "competitive programming", "python"))
             // function for suggestionSection 
             suggestionSection()
              // this is for course secation
            CourseSection(
                  // function require list of courses and
                  // one course contain 5 attributes
                courses = listOf(
                    Course(
                        title = "geek of the year",
                        R.drawable.ic_headphone,
                          // these are colors.......
                        BlueViolet1,
                        BlueViolet2,
                        BlueViolet3
                    ),
                      // below are the copies of the objects
                      // and you can add as many as you want
                    Course(
                        title = "How does AI Works",
                        R.drawable.ic_videocam,
                        LightGreen1,
                        LightGreen2,
                        LightGreen3
                    ),
                    Course(
                        title = "Advance python Course",
                        R.drawable.ic_play,
                        skyblue1,
                        skyblue2,
                        skyblue3
                    ),
                    Course(
                        title = "Advance Java Course",
                        R.drawable.ic_headphone,
                        Beige1,
                        Beige2,
                        Beige3
                    ),
                    Course(
                        title = "prepare for aptitude test",
                        R.drawable.ic_play,
                        OrangeYellow1,
                        OrangeYellow2,
                        OrangeYellow3
                    ),
                    Course(
                        title = "How does AI Works",
                        R.drawable.ic_videocam,
                        LightGreen1,
                        LightGreen2,
                        LightGreen3
                    ),
                )
            )
        }
        // this is the final one that is bottomMenu
        BottomMenu(items = listOf(
              // having 5 instances
            BottomMenuContent("Home", R.drawable.ic_home),
            BottomMenuContent("explore", R.drawable.ic_baseline_explore_24),
            BottomMenuContent("dark mode", R.drawable.ic_moon),
            BottomMenuContent("videos", R.drawable.ic_videocam),
            BottomMenuContent("Profile", R.drawable.ic_profile),
        ), modifier = Modifier.align(Alignment.BottomCenter))
    }
}


Now add fun HomeScreen() that contains all the functions, in MainActivity as 

Kotlin




package com.cuid.geekscourses
 
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import com.cuid.geekscourses.ui.HomeScreen
import com.cuid.geekscourses.ui.theme.Geekscourse
 
class MainActivity : ComponentActivity() {
    @ExperimentalFoundationApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Geekscourse{
                HomeScreen()
            }
        }
    }
}


Finally, Our UI is looking like this:

Output:

Project Link: Click Here



Last Updated : 15 Nov, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads