Basic Android Compose - User Rating Bar

Ken Ruiz Inoue
Deuk
Published in
6 min readJan 4, 2024

Introduction

Welcome to another tutorial on Android Jetpack Compose, where we delve into building a dynamic and customizable User Rating Bar. Whether new to Android Compose or looking to expand your skill set, this tutorial is for you!

Environment

  • Android Studio Hedgehog | 2023.1.1
  • Compose version: androidx.compose:compose-bom:2023.08.00
  • Pixel 6 API 30 Emulator

Step 1: User Rating Bar Implementation

To get started, download the necessary icons from here and move them into your project's res/drawable directory.

Next, create a Kotlin file named UserRatingBar.kt and populate it with the following code:

// Your package...

import android.view.MotionEvent
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
fun UserRatingBar(
// 1. Parameters for UserRatingBar
modifier: Modifier = Modifier,
size: Dp = 64.dp,
ratingState: MutableState<Int> = remember { mutableIntStateOf(0) },
ratingIconPainter: Painter = painterResource(id = R.drawable.ic_star),
selectedColor: Color = Color(0xFFFFD700),
unselectedColor: Color = Color(0xFFA2ADB1)
) {
Row(modifier = modifier.wrapContentSize()) {
// 2. Star Icon Generation Loop
for (value in 1..5) {
StarIcon(
size = size,
painter = ratingIconPainter,
ratingValue = value,
ratingState = ratingState,
selectedColor = selectedColor,
unselectedColor = unselectedColor
)
}
}
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun StarIcon(
// 3. Parameters for StarIcon
size: Dp,
ratingState: MutableState<Int>,
painter: Painter,
ratingValue: Int,
selectedColor: Color,
unselectedColor: Color
) {
// 4. Color Animation
val tint by animateColorAsState(
targetValue = if (ratingValue <= ratingState.value) selectedColor else unselectedColor,
label = ""
)

Icon(
painter = painter,
contentDescription = null,
modifier = Modifier
.size(size)
// 5. Touch Interaction Handling
.pointerInteropFilter {
when (it.action) {
MotionEvent.ACTION_DOWN -> {
ratingState.value = ratingValue
}
}
true
},
tint = tint
)
}

@Preview
@Composable
fun PreviewUserRatingBar() {
val ratingState = remember { mutableIntStateOf(0) }
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
UserRatingBar(ratingState = ratingState)
}
}
  1. Parameters for UserRatingBar(): This section outlines the parameters used in the UserRatingBar() composable function. The modifier is a versatile layout tool for adjusting appearance or arrangement, defaulting to no modifications. The size parameter sets each star icon's dimension, here defaulted to 64.dp. The ratingState plays a pivotal role; it is a mutable integer state that not only tracks the current rating, but also allows for the exposure of the selected rating value outside the composable. Such an approach is fundamental in Compose, where composables are designed to be modular and interoperable, allowing for seamless data flow and reusability. The ratingIconPainter parameter uses the ic_star drawable for star rendering. Finally, selectedColor and unselectedColor determine the star icons' colors in their selected and unselected states, respectively.
  2. Star Icon Generation Loop: This section utilizes a simple Row layout combined with a for loop to generate a series of five star icons, each ranging from 1 to 5 in value. The StarIcon() function creates each interactive star, symbolizing a potential rating value. In this scenario, where the number of elements is small and fixed, a LazyRow is not required. LazyRow is typically used for larger, dynamic lists where offscreen items can be lazily loaded to improve performance.
  3. Parameters for StarIcon(): This section configures each StarIcon(), a rating bar component. While it shares some parameters with UserRatingBar(), like size, ratingState, selectedColor, and unselectedColor, it introduces ratingValue. The ratingValue is specific to each star, representing its contribution to the overall rating.
  4. Color Animation: This part is integral to the user experience of the rating system. This animation smoothly transitions each star's color between unselectedColor and selectedColor in response to the current rating.
  5. Touch Interaction Handling: This part of the StarIcon function adds an interaction layer to the icon. It uses pointerInteropFilter to handle touch events. Specifically, when a star is touched (MotionEvent.ACTION_DOWN), it updates the ratingState value to the star's ratingValue, effectively changing the number of selected stars in the rating bar.

Upon running the PreviewUserRatingBar() function, you will observe the functioning UserRatingBar() as illustrated below:

PreviewUserRatingBar()

Step 2: Customizing the UI in MainActivity

Next, we will integrate the UserRatingBar() into the MainActivit.kt and customize it with specific parameters. Update it as follows:

// Your package...

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.*
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.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
// 1. Rating State
val ratingState = remember { mutableIntStateOf(0) }
UserRatingBar(
// 2. Customized UserRatingBar
ratingState = ratingState,
ratingIconPainter = painterResource(id = R.drawable.ic_star_2),
size = 48.dp,
selectedColor = Color(0xFF5A966E),
)
// 3. Current Selected Value Feedback
Text(
text = "Current Rating Bar Value: ${ratingState.intValue}",
fontWeight = FontWeight.Bold,
fontSize = 20.sp
)
}
}
}
}
  1. Rating State: In the MainActivity, a ratingState variable is created to track the current rating value. This state is initialized with remember { mutableIntStateOf(0) }, setting the default rating to zero (no stars selected). It's a mutable state, meaning it can change over time. This state is crucial as it enables the rating bar to update its display based on user interactions, reflecting the current number of stars the user selects.
  2. Customized UserRatingBar(): The UserRatingBar() composable function is customized within MainActivity. The earlier defined ratingState is passed to this function to synchronize the rating bar's state with the UI. Customization includes using a different star icon (ratingIconPainter), adjusting the size of the stars (size), and setting a unique color for selected stars (selectedColor). These customizations allow the rating bar to be tailored to specific design requirements, demonstrating the flexibility of Compose in UI design.
  3. Current Selected Value Feedback: This part involves displaying the current rating value to the user. A Text() composable is used to show a message that dynamically includes the current value of ratingState. This feedback mechanism is important for enhancing user experience by providing immediate, clear feedback about their selected rating. The text updates in real-time as the ratingState changes, showcasing the reactive nature of the Compose framework.

When the application is executed, the selected rating’s feedback will be displayed in a text element beneath the UserRatingBar().

User Rating Bar with Feedback

Wrapping Up

Congratulations on completing the tutorial! Now, you’re all set to seamlessly incorporate this User Rating Bar UI into your projects. Dive in and see how it enhances your app’s functionality and user experience!

🔗 Access the Full Code: Click here to access the complete codebase for our User Rating Bar tutorial.

👍 Feedback and Support: Thank you for taking the time to read through this tutorial. I hope you found it informative and engaging. If you have any questions or need further clarification on any part of the tutorial, please feel free to reach out. Your feedback and interaction are highly appreciated, so don’t hesitate to leave your claps and follow for more content like this.

Looking forward to seeing you in my upcoming articles!

Discover More

Are you eager for more knowledge? Dive into my Android Compose Tutorials Library. These tutorials cover a wide spectrum of UI design techniques in Jetpack Compose. Each guide is meticulously crafted to enhance your skills and creativity in Android development!

Deuk Services: Your Gateway to Leading Android Innovation

Are you looking to boost your business with top-tier Android solutions?Partner with Deuk services and take your projects to unparalleled heights.

--

--