Last active
August 29, 2021 23:43
-
-
Save JorgeCastilloPrz/1813e322acc2e153a8e7869cd969a032 to your computer and use it in GitHub Desktop.
Composable to show rating stars. Noninteractive.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.compose.foundation.Image | |
import androidx.compose.foundation.layout.Row | |
import androidx.compose.foundation.layout.padding | |
import androidx.compose.foundation.layout.preferredSize | |
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.ColorFilter | |
import androidx.compose.ui.graphics.painter.Painter | |
import androidx.compose.ui.layout.Layout | |
import androidx.compose.ui.platform.LocalDensity | |
import androidx.compose.ui.res.painterResource | |
import androidx.compose.ui.text.font.FontWeight | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.compose.ui.unit.dp | |
/** | |
* Composable to render 5 stars followed by the total number of votes. | |
*/ | |
@Composable | |
fun Rating(rating: Float, votes: Long, modifier: Modifier = Modifier) { | |
val ratingOverFive = rating / 2 // it comes over 10 from the API | |
Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { | |
RatingStars(ratingOverFive) | |
Text( | |
modifier = Modifier.padding(start = 4.dp), | |
text = "($votes)", | |
color = warnings, | |
style = MaterialTheme.typography.subtitle2.copy(fontWeight = FontWeight.Black) | |
) | |
} | |
} | |
@Composable | |
private fun RatingStars(ratingOverFive: Float) { | |
val maxWidth = with(LocalDensity.current) { 100.dp.toPx() }.toInt() | |
val maxHeight = with(LocalDensity.current) { 20.dp.toPx() }.toInt() | |
Layout( | |
content = { | |
(1..5).forEach { position -> | |
Image( | |
modifier = Modifier.preferredSize(20.dp), | |
painter = starPainterFor(position, ratingOverFive), | |
contentDescription = null, | |
colorFilter = ColorFilter.tint(warnings) | |
) | |
} | |
} | |
) { measurables, constraints -> | |
// Measure children with given constraints | |
// Measure each children to get a placeable back | |
val placeables = measurables.map { measurable -> | |
// Measure each children | |
val starConstraints = constraints.copy(maxWidth = constraints.maxWidth / 5) | |
measurable.measure(starConstraints) | |
} | |
// Set the size of the layout as big as it can | |
layout(maxWidth, maxHeight) { | |
var xPos = 0 | |
// Place the stars | |
placeables.forEach { placeable -> | |
placeable.placeRelative(x = xPos, y = 0) | |
xPos += placeable.width | |
} | |
} | |
} | |
} | |
@Composable | |
private fun starPainterFor(position: Int, ratingOverFive: Float): Painter = | |
when { | |
ratingOverFive >= position -> { | |
painterResource(id = R.drawable.ic_star_full) | |
} | |
ratingOverFive >= position - 0.5f -> { | |
painterResource(id = R.drawable.ic_star_half) | |
} | |
else -> { | |
painterResource(id = R.drawable.ic_star_empty) | |
} | |
} | |
@Preview | |
@Composable | |
fun RatingPreview() { | |
Rating(4.5f, 1257) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That's good to hear; I didn't have the larger context of the gist. Thanks for the explanation!