Interface to hold information about a Carousel item and its size.
FadingHorizontalMultiBrowseCarouselSample
@Preview
@Composable
fun FadingHorizontalMultiBrowseCarouselSample() {
data class CarouselItem(
val id: Int,
@DrawableRes val imageResId: Int,
@StringRes val contentDescriptionResId: Int,
)
val items =
listOf(
CarouselItem(0, R.drawable.carousel_image_1, R.string.carousel_image_1_description),
CarouselItem(1, R.drawable.carousel_image_2, R.string.carousel_image_2_description),
CarouselItem(2, R.drawable.carousel_image_3, R.string.carousel_image_3_description),
CarouselItem(3, R.drawable.carousel_image_4, R.string.carousel_image_4_description),
CarouselItem(4, R.drawable.carousel_image_5, R.string.carousel_image_5_description),
)
val state = rememberCarouselState { items.count() }
HorizontalMultiBrowseCarousel(
state = state,
modifier = Modifier.width(412.dp).height(221.dp),
preferredItemWidth = 186.dp,
itemSpacing = 8.dp,
contentPadding = PaddingValues(horizontal = 16.dp),
) { i ->
val item = items[i]
// For item 1 and 4, create a stacked item layout that clips two images independently
// to the item's mask
if (i == 1 || i == 4) {
Column(
modifier = Modifier.height(205.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Image(
modifier =
Modifier.fillMaxWidth()
.fillMaxHeight(.5f)
.maskClip(MaterialTheme.shapes.extraLarge)
.maskBorder(
BorderStroke(3.dp, Color.Magenta),
MaterialTheme.shapes.extraLarge,
),
painter = painterResource(id = item.imageResId),
contentDescription = stringResource(item.contentDescriptionResId),
contentScale = ContentScale.Crop,
)
Image(
modifier =
Modifier.fillMaxSize()
.maskClip(RoundedCornerShape(8.dp))
.maskBorder(BorderStroke(5.dp, Color.Green), RoundedCornerShape(8.dp)),
painter = painterResource(id = item.imageResId),
contentDescription = stringResource(item.contentDescriptionResId),
contentScale = ContentScale.Crop,
)
}
} else {
// Mask using a generic path shape
val pathShape = remember {
object : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density,
): Outline {
val roundRect =
RoundRect(0f, 0f, size.width, size.height, CornerRadius(30f))
val shapePath = Path().apply { addRoundRect(roundRect) }
return Outline.Generic(shapePath)
}
}
}
Box(
modifier =
Modifier.height(205.dp)
.maskClip(pathShape)
.maskBorder(BorderStroke(5.dp, Color.Red), pathShape)
) {
Image(
painter = painterResource(id = item.imageResId),
contentDescription = stringResource(item.contentDescriptionResId),
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
ElevatedAssistChip(
onClick = { /* Do something! */ },
label = { Text("Image $i") },
modifier =
Modifier.graphicsLayer {
// Fade the chip in once the carousel item's size is large enough to
// display the entire chip
alpha =
lerp(
0f,
1f,
max(
size.width - (carouselItemDrawInfo.maxSize) +
carouselItemDrawInfo.size,
0f,
) / size.width,
)
// Translate the chip to be pinned to the left side of the item's mask
translationX = carouselItemDrawInfo.maskRect.left + 8.dp.toPx()
},
leadingIcon = {
Icon(
Icons.Filled.Image,
contentDescription = "Localized description",
Modifier.size(AssistChipDefaults.IconSize),
)
},
)
}
}
}
}