2

I'm trying to implement a rating bar. I refer to https://gist.github.com/vitorprado/0ae4ad60c296aefafba4a157bb165e60 but I don't understand anything from this code. It works but when I use this code the stars don't have rounded corners. I want to implement something like the following :

Jarnojr
  • 543
  • 1
  • 7
  • 18

3 Answers3

11

I made very basic sample for this, it would give the basic idea for creating rating bar with sample border and filled png files.

@Composable
private fun RatingBar(
    modifier: Modifier = Modifier,
    rating: Float,
    spaceBetween: Dp = 0.dp
) {

    val image = ImageBitmap.imageResource(id = R.drawable.star)
    val imageFull = ImageBitmap.imageResource(id = R.drawable.star_full)

    val totalCount = 5

    val height = LocalDensity.current.run { image.height.toDp() }
    val width = LocalDensity.current.run { image.width.toDp() }
    val space = LocalDensity.current.run { spaceBetween.toPx() }
    val totalWidth = width * totalCount + spaceBetween * (totalCount - 1)


    Box(
        modifier
            .width(totalWidth)
            .height(height)
            .drawBehind {
                drawRating(rating, image, imageFull, space)
            })
}

private fun DrawScope.drawRating(
    rating: Float,
    image: ImageBitmap,
    imageFull: ImageBitmap,
    space: Float
) {

    val totalCount = 5

    val imageWidth = image.width.toFloat()
    val imageHeight = size.height

    val reminder = rating - rating.toInt()
    val ratingInt = (rating - reminder).toInt()

    for (i in 0 until totalCount) {

        val start = imageWidth * i + space * i

        drawImage(
            image = image,
            topLeft = Offset(start, 0f)
        )
    }

    drawWithLayer {
        for (i in 0 until totalCount) {
            val start = imageWidth * i + space * i
            // Destination
            drawImage(
                image = imageFull,
                topLeft = Offset(start, 0f)
            )
        }

        val end = imageWidth * totalCount + space * (totalCount - 1)
        val start = rating * imageWidth + ratingInt * space
        val size = end - start

        // Source
        drawRect(
            Color.Transparent,
            topLeft = Offset(start, 0f),
            size = Size(size, height = imageHeight),
            blendMode = BlendMode.SrcIn
        )
    }
}

private fun DrawScope.drawWithLayer(block: DrawScope.() -> Unit) {
    with(drawContext.canvas.nativeCanvas) {
        val checkPoint = saveLayer(null, null)
        block()
        restoreToCount(checkPoint)
    }
}

Usage

Column {
    RatingBar(rating = 3.7f, spaceBetween = 3.dp)
    RatingBar(rating = 2.5f, spaceBetween = 2.dp)
    RatingBar(rating = 4.5f, spaceBetween = 2.dp)
    RatingBar(rating = 1.3f, spaceBetween = 4.dp)
}

Result

enter image description here

Also created a library that uses gestures, other png files and vectors as rating items is available here.

@Composable
fun RatingBar(
  modifier: Modifier = Modifier,
  rating: Float,
  painterEmpty: Painter,
  painterFilled: Painter,
  tintEmpty: Color? = DefaultColor,
  tintFilled: Color? = null,
  itemSize: Dp = Dp.Unspecified,
  rateChangeMode: RateChangeMode = RateChangeMode.AnimatedChange(),
  gestureMode: GestureMode = GestureMode.DragAndTouch,
  shimmer: Shimmer? = null,
  itemCount: Int = 5,
  space: Dp = 0.dp,
  ratingInterval: RatingInterval = RatingInterval.Unconstrained,
  allowZeroRating: Boolean = true,
  onRatingChangeFinished: ((Float) -> Unit)? = null,
  onRatingChange: (Float) -> Unit
)

enter image description here

Thracian
  • 43,021
  • 16
  • 133
  • 222
0

You could try this library

Add in project build.gradle:

repositories {
    maven { url 'https://jitpack.io' }
}

App build.gradle

dependencies {
   implementation 'com.github.a914-gowtham:compose-ratingbar:1.2.5'
}

Usage

   import androidx.compose.runtime.*

   var rating: Float by remember { mutableStateOf(initialRating) }

   RatingBar(
       value = rating,
       config = RatingBarConfig()
           .style(RatingBarStyle.HighLighted),
       onValueChange = {
           rating = it
       },
       onRatingChanged = {
           Log.d("TAG", "onRatingChanged: $it")
       }
   )
gowtham6672
  • 999
  • 1
  • 10
  • 22
-1

You can pass the custom drawable as icon. check this code.

Replace your RatingStar() function as it is using canvas to draw star, instead pass the custom drawable.

  @Composable
  private fun starShow(){
           val icon = if (isSelected)
           //your selected drawable
          else
         //your unselected drawable
  

              Icon(
               painter = painterResource(id = icon),
               contentDescription = null,
               tint = MyColor.starColor)
     }
Ankit
  • 335
  • 1
  • 10