Chandresh Parmar
Chandresh Parmar

Reputation: 205

How to expand FAB into a Sheet in Jetpack Compose?

I'm trying to create a Material 3 Floating Action Button in Jetpack Compose that expands into a Sheet with multiple options on click. I'm trying to achieve something like this:

Material 3 Fab Transform

The above example is from the Material 3 website. However, I haven't got any idea on how to implement such a thing. I tried searching for it online but almost all of the tutorials show transforming a FAB into multiple other FABs on click.

I tried modifying an ExtendedFloatingActionButton but didn't get the results I wanted. I also tried using AnimatedContent to animate between a normal FloatingActionButton and a Column with multiple Rows containing other options but still couldn't get the required results.

Any guidance would be appreciated. Thanks in advance!

Upvotes: 4

Views: 2962

Answers (2)

MannB1023
MannB1023

Reputation: 100

I got it to be nearly identical, you dont need everything here, some of the parameters were specific to fit in my code. Expandable basically just enables that the fab can be used on multiple different screens, allowing you to choose whether or not it expands. You can get rid of that if you want, same with the other parameters.

    // Custom fab that allows for displaying extended content
    @Composable
    fun CustomFloatingActionButton(
        expandable: Boolean,
        onFabClick: () -> Unit,
        fabIcon: ImageVector
    ) {
        var isExpanded by remember { mutableStateOf(false) }
        if (!expandable) { // Close the expanded fab if you change to non expandable nav destination
            isExpanded = false
        }

        val fabSize = 64.dp
        val expandedFabWidth by animateDpAsState(
            targetValue = if (isExpanded) 200.dp else fabSize,
            animationSpec = spring(dampingRatio = 3f)
        )
        val expandedFabHeight by animateDpAsState(
            targetValue = if (isExpanded) 58.dp else fabSize,
            animationSpec = spring(dampingRatio = 3f)
        )

        Column {

            // ExpandedBox over the FAB
            Box(
                modifier = Modifier
                    .offset(y = (25).dp)
                    .size(
                        width = expandedFabWidth,
                        height = (animateDpAsState(if (isExpanded) 225.dp else 0.dp, animationSpec = spring(dampingRatio = 4f))).value)
                    .background(
                        MaterialTheme.colorScheme.surfaceContainer,
                        shape = RoundedCornerShape(18.dp)
                    )
            ) {
                // Customize the content of the expanded box as needed
            }

            FloatingActionButton(
                onClick = {
                    onFabClick()
                    if (expandable) {
                        isExpanded = !isExpanded
                    }
                },
                modifier = Modifier
                    .width(expandedFabWidth)
                    .height(expandedFabHeight),
                shape = RoundedCornerShape(18.dp)

            ) {

                Icon(
                    imageVector = fabIcon,
                    contentDescription = null,
                    modifier = Modifier
                        .size(24.dp)
                        .offset(x = animateDpAsState(if (isExpanded) -70.dp else 0.dp, animationSpec = spring(dampingRatio = 3f)).value)
                )

                Text(
            text = "Create Reminder",
            softWrap = false,
            modifier = Modifier
                .offset(x = animateDpAsState(if (isExpanded) 10.dp else 50.dp, animationSpec = spring(dampingRatio = 3f)).value)
                .alpha(
                    animateFloatAsState(
                        targetValue = if (isExpanded) 1f else 0f,
                        animationSpec = tween(
                            durationMillis = if (isExpanded) 350 else 100,
                            delayMillis = if (isExpanded) 100 else 0,
                            easing = EaseIn)).value)
        )

    }
}
}

Upvotes: 4

Raafat Alhmidi
Raafat Alhmidi

Reputation: 1176

In material 3 this behaviour called Container transform you can check a sample for it here

it's planned to be in compose but its not there yet unfortunately check this

here you can find some guild-lines and best practises for designing a container transform pattern

for your exact request you an do it using updateTransition and AnimatedVisibility or AnimatedContent apis.

Upvotes: 1

Related Questions