You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Material3中通过Jetpack Compose实现FAB转菜单效果?

在Jetpack Compose Material3中实现FAB转菜单的动效

我想在Material3(M3)里用Jetpack Compose实现浮动操作按钮(FAB)转换为菜单的动效,试过官方的FloatingActionMenu但效果不符合需求。现有基础缩放动画代码如下:

// Scale Animation
val scale by animateFloatAsState(
    targetValue = if (isPressed) 0.9f else 1f,
    animationSpec = tween(150, easing = FastOutSlowInEasing)
)

FloatingActionButton(
    modifier = Modifier.scale(scale),
    onClick = { /* Handle click */ }
) { Icon(Icons.Default.Add, null) }

目标效果参考图:
FAB转菜单动效

参考M3动效规范中的「FAB转菜单」转场模式。


实现思路

通过状态控制主FAB的旋转、缩放动画,同时联动子菜单按钮的偏移、透明度动画,还原M3规范里的转场效果。核心是利用Compose的动画API(animateFloatAsState、animateOffsetAsState)实现状态驱动的动效同步。

完整实现代码

import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp

@Composable
fun FabToMenuTransition() {
    var isExpanded by remember { mutableStateOf(false) }
    
    // 主FAB旋转动画:Add图标转为关闭样式
    val rotation by animateFloatAsState(
        targetValue = if (isExpanded) 45f else 0f,
        animationSpec = tween(300, easing = FastOutSlowInEasing)
    )
    
    // 主FAB缩放动画
    val fabScale by animateFloatAsState(
        targetValue = if (isExpanded) 0.85f else 1f,
        animationSpec = tween(250, easing = FastOutSlowInEasing)
    )
    
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomEnd) {
        // 子菜单:编辑按钮
        val editOffset by animateOffsetAsState(
            targetValue = if (isExpanded) Offset(x = 0f, y = -80.dp.toPx()) else Offset.Zero,
            animationSpec = tween(300, easing = FastOutSlowInEasing)
        )
        if (isExpanded || editOffset.y != 0f) {
            FloatingActionButton(
                modifier = Modifier
                    .offset { editOffset }
                    .graphicsLayer { alpha = if (isExpanded) 1f else 0f },
                onClick = { /* 处理编辑操作 */ },
                containerColor = MaterialTheme.colorScheme.secondaryContainer
            ) {
                Icon(Icons.Default.Edit, contentDescription = "编辑")
            }
        }
        
        // 子菜单:删除按钮
        val deleteOffset by animateOffsetAsState(
            targetValue = if (isExpanded) Offset(x = 0f, y = -160.dp.toPx()) else Offset.Zero,
            animationSpec = tween(350, easing = FastOutSlowInEasing)
        )
        if (isExpanded || deleteOffset.y != 0f) {
            FloatingActionButton(
                modifier = Modifier
                    .offset { deleteOffset }
                    .graphicsLayer { alpha = if (isExpanded) 1f else 0f },
                onClick = { /* 处理删除操作 */ },
                containerColor = MaterialTheme.colorScheme.errorContainer
            ) {
                Icon(Icons.Default.Delete, contentDescription = "删除")
            }
        }
        
        // 主FAB
        FloatingActionButton(
            modifier = Modifier
                .padding(16.dp)
                .graphicsLayer {
                    scaleX = fabScale
                    scaleY = fabScale
                    rotationZ = rotation
                },
            onClick = { isExpanded = !isExpanded }
        ) {
            Icon(Icons.Default.Add, contentDescription = if (isExpanded) "关闭菜单" else "打开菜单")
        }
    }
}

关键细节说明

  • 主FAB动效:通过rotationZ实现Add图标旋转45度模拟关闭符号,配合缩放动画强化交互反馈
  • 子菜单动效:用animateOffsetAsState让子按钮从主FAB位置向上滑动展开,同时控制透明度实现淡入淡出
  • 状态联动:通过isExpanded状态统一触发所有动画,保证动效同步流畅
  • 动效曲线:使用M3推荐的FastOutSlowInEasing,确保动画符合Material设计的自然流畅感

内容的提问来源于stack exchange,提问作者Muhammad Awais

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:12:44