by @alexstyl
✉️ Leave your feedback

← Back to Tv Material

Carousel

Component
in
Tv Material
. Since 1.0.0-alpha07

Overview

Examples

Community Notes

Video

@Composable
fun SimpleCarousel() {
    @Composable
    fun Modifier.onFirstGainingVisibility(onGainingVisibility: () -> Unit): Modifier {
        var isVisible by remember { mutableStateOf(false) }
        LaunchedEffect(isVisible) {
            if (isVisible) onGainingVisibility()
        }

        return onPlaced { isVisible = true }
    }

    @Composable
    fun Modifier.requestFocusOnFirstGainingVisibility(): Modifier {
        val focusRequester = remember { FocusRequester() }
        return focusRequester(focusRequester)
            .onFirstGainingVisibility { focusRequester.requestFocus() }
    }

    val backgrounds = listOf(
        Color.Red.copy(alpha = 0.3f),
        Color.Yellow.copy(alpha = 0.3f),
        Color.Green.copy(alpha = 0.3f)
    )

    var carouselFocused by remember { mutableStateOf(false) }
    Carousel(
        itemCount = backgrounds.size,
        modifier = Modifier
            .height(300.dp)
            .fillMaxWidth()
            .onFocusChanged { carouselFocused = it.isFocused },
        contentTransformEndToStart =
        fadeIn(tween(1000)).togetherWith(fadeOut(tween(1000))),
        contentTransformStartToEnd =
        fadeIn(tween(1000)).togetherWith(fadeOut(tween(1000)))
    ) { itemIndex ->
        Box(
            modifier = Modifier
                .background(backgrounds[itemIndex])
                .border(2.dp, Color.White.copy(alpha = 0.5f))
                .fillMaxSize()
        ) {
            var buttonFocused by remember { mutableStateOf(false) }
            val buttonModifier =
                if (carouselFocused) {
                    Modifier.requestFocusOnFirstGainingVisibility()
                } else {
                    Modifier
                }

            Button(
                onClick = { },
                modifier = buttonModifier
                    .onFocusChanged { buttonFocused = it.isFocused }
                    .padding(40.dp)
                    .border(
                        width = 2.dp,
                        color = if (buttonFocused) Color.Red else Color.Transparent,
                        shape = RoundedCornerShape(50)
                    )
                    // Duration of animation here should be less than or equal to carousel's
                    // contentTransform duration to ensure the item below does not disappear
                    // abruptly.
                    .animateEnterExit(
                        enter = slideInHorizontally(animationSpec = tween(1000)) { it / 2 },
                        exit = slideOutHorizontally(animationSpec = tween(1000))
                    )
                    .padding(vertical = 2.dp, horizontal = 5.dp)
            ) {
                Text(text = "Play")
            }
        }
    }
}
@Composable
fun CarouselIndicatorWithRectangleShape() {
    val backgrounds = listOf(
        Color.Red.copy(alpha = 0.3f),
        Color.Yellow.copy(alpha = 0.3f),
        Color.Green.copy(alpha = 0.3f)
    )
    val carouselState = rememberCarouselState()

    Carousel(
        itemCount = backgrounds.size,
        modifier = Modifier
            .height(300.dp)
            .fillMaxWidth(),
        carouselState = carouselState,
        carouselIndicator = {
            CarouselDefaults.IndicatorRow(
                itemCount = backgrounds.size,
                activeItemIndex = carouselState.activeItemIndex,
                modifier = Modifier
                    .align(Alignment.BottomEnd)
                    .padding(16.dp),
                indicator = { isActive ->
                    val activeColor = Color.Red
                    val inactiveColor = activeColor.copy(alpha = 0.5f)
                    Box(
                        modifier = Modifier
                            .size(8.dp)
                            .background(
                                color = if (isActive) activeColor else inactiveColor,
                                shape = RectangleShape,
                            ),
                    )
                }
            )
        },
        contentTransformEndToStart =
        fadeIn(tween(1000)).togetherWith(fadeOut(tween(1000))),
        contentTransformStartToEnd =
        fadeIn(tween(1000)).togetherWith(fadeOut(tween(1000)))
    ) { itemIndex ->
        Box(
            modifier = Modifier
                .background(backgrounds[itemIndex])
                .border(2.dp, Color.White.copy(alpha = 0.5f))
                .fillMaxSize()
        ) {
            var isFocused by remember { mutableStateOf(false) }
            Button(
                onClick = { },
                modifier = Modifier
                    .onFocusChanged { isFocused = it.isFocused }
                    // Duration of animation here should be less than or equal to carousel's
                    // contentTransform duration to ensure the item below does not disappear
                    // abruptly.
                    .animateEnterExit(
                        enter = slideInHorizontally(animationSpec = tween(1000)) { it / 2 },
                        exit = slideOutHorizontally(animationSpec = tween(1000))
                    )
                    .padding(40.dp)
                    .border(
                        width = 2.dp,
                        color = if (isFocused) Color.Red else Color.Transparent,
                        shape = RoundedCornerShape(50)
                    )
                    .padding(vertical = 2.dp, horizontal = 5.dp)
            ) {
                Text(text = "Play")
            }
        }
    }
}
Previous ComponentCard
Next ComponentCarouselItem