CarouselItemDrawInfo
Interface
Common
@ExperimentalMaterial3Api
sealed interface CarouselItemDrawInfo
Interface to hold information about a Carousel item and its size.
Example of CarouselItemDrawInfo usage:
Properties
Common
val size: Float
The size of the carousel item in the main axis in pixels
Common
val minSize: Float
The minimum size of the carousel item in the main axis in pixels, eg. the size of the item as it scrolls off the sides of the carousel
Common
val maxSize: Float
The maximum size of the carousel item in the main axis in pixels, eg. the size of the item when it is at a focal position
Common
val maskRect: Rect
The Rect
by which the carousel item is being clipped.
Code Examples
FadingHorizontalMultiBrowseCarouselSample
@OptIn(ExperimentalMaterial3Api::class)
@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),
)
},
)
}
}
}
}