在我的Android项目中,我正在做一个简单的浮动操作按钮,它可以展开并显示执行不同操作的按钮列表. 为了跟踪FAB的当前状态,我有下一个枚举类

enum class FabState {
    Expanded,
    Collapsed
}

为了显示浮动操作按钮,我有以下可组合函数:

@Composable
fun MultiFloatingActionButton(
    icon: ImageVector,
    iconTint: Color = Color.White,
    miniFabItems: List<MinFabItem>,
    fabState: FabState, //The initial state of the FAB
    onFabStateChanged: (FabState) -> Unit,
    onItemClick: (MinFabItem) -> Unit
) {
    val transition = updateTransition(targetState = fabState, label = "transition")

    val rotate by transition.animateFloat(label = "rotate") {
        when (it) {
            FabState.Collapsed -> 0f
            FabState.Expanded -> 315f
        }
    }

    val fabScale by transition.animateFloat(label = "fabScale") {
        when (it) {
            FabState.Collapsed -> 0f
            FabState.Expanded -> 1f
        }
    }

    val alpha by transition.animateFloat(label = "alpha") {
        when (it) {
            FabState.Collapsed -> 0f
            FabState.Expanded -> 1f
        }
    }

    val shadow by transition.animateDp(label = "shadow", transitionSpec = { tween(50) }) { state ->
        when (state) {
            FabState.Expanded -> 2.dp
            FabState.Collapsed -> 0.dp
        }
    }

    Column(
        horizontalAlignment = Alignment.End
    ) { // This is where I have my question, in the if condition
        if (fabState == FabState.Expanded || transition.currentState == FabState.Expanded) {
            miniFabItems.forEach { minFabItem ->
                MinFab( //Composable for creating sub action buttons
                    fabItem = minFabItem,
                    alpha = alpha,
                    textShadow = shadow,
                    fabScale = fabScale,
                    onMinFabItemClick = {
                        onItemClick(minFabItem)
                    }
                )
                Spacer(modifier = Modifier.size(16.dp))
            }
        }

        FloatingActionButton(
            onClick = {
                onFabStateChanged(
                    when (fabState) {
                        FabState.Expanded -> {
                            FabState.Collapsed
                        }
                        FabState.Collapsed -> {
                            FabState.Expanded
                        }
                    }
                )
            }
        ) {
            Icon(
                imageVector = icon,
                tint = iconTint,
                contentDescription = null,
                modifier = Modifier.rotate(rotate)
            )
        }
    }
}

我定义的常量用于根据FAB状态显示/隐藏按钮的动画.

当我第一次做这个函数时,最初的条件给了我一个不同的行为,并try 了所有可能的条件,我得到了3个不同的结果:

  • 第一个条件: if (transition.currentState == FabState.Expanded) {...}

结果:animation not loading from collapsed to expanded, but it does from expanded to collapsed

  • 第二种情况:if (fabState == FabState.Expanded) {...}

结果:animation loading from collapsed to expanded, but not from expanded to collapsed

第三个条件(我现在正在使用的条件): if (fabState == FabState.Expanded || transition.currentState == FabState.Expanded) {...}

结果:animation loading in both ways

所以我的问题是:每一种情况是如何改变动画的行为的?

任何帮助都将不胜感激.提前谢谢你

推荐答案

在调用onFabStateChanged时立即更新fabState,并在结束转换时更新transition.currentState,并且transition.isRunning返回FALSE

仅当可合成对象出现在树中时,才会发生动画.如果If块中的条件为FALSE,则这些元素不可用于动画.

条件1在Enter Perion期间为FALSE,中断进入动画;条件2在退出期间为FALSE,中断退出动画,并且在退出后两者均为FALSE.因此,合并它们解决了您的问题,并在不需要时从树中删除了可组合组件.

更好的方法

AnimatedVisibility(
    visible = fabState == FabState.Expanded,
    enter = fadeIn()+ scaleIn(),
    exit = fadeOut() + scaleOut(),
) {
    miniFabItems.forEach { minFabItem ->
        MinFab(
            fabItem = minFabItem,
            textShadow = 0.dp,
            onMinFabItemClick = {
                onItemClick(minFabItem)
            }
        )
        Spacer(modifier = Modifier.size(16.dp))
    }
}

并使用graphicsLayer修饰符而不是rotate

Icon(
    imageVector = Icons.Default.Add,
    tint = Color.White,
    contentDescription = null,
    modifier = Modifier
        .graphicsLayer {
            this.rotationZ = rotate
        }
)

Android相关问答推荐

为什么使用. DeliverveAsState()时会出现空指针异常?

KMM项目生成错误-';在项目';中找不到测试类:共享';

fillMaxHeight中的分数在列内不起作用(android jetpack compose)

替换- prop -中的值(adb shell getprop)

无法在Jetpack Compose中显示Admob原生广告

我如何剪裁一个可由另一个合成的

如何修复Google Play市场中有关已删除广告库的错误消息?

如何解决Gradle构建错误:java.lang.NoSuchMethodError

Kotlin为多个控件设置一个侦听器

Jetpack Compose:如何将文本放置在行的右侧?

弹出导航堆栈后,Compose 无法访问 Hilt View Model

Jetpack Compose 使用 SavedStateHandle 发送返回结果不适用于 ViewModel 中注入的 SavedStateHandle

如何禁用自动登录 google play games services android unity?

相机2问题:设置AE区域、AF区域和AWB区域.

Horizo​​ntalPager 的可组合物中的 LaunchedEffect 问题

Android Studio 错误要求依赖它的库和应用程序针对 Android API 的 33 版或更高版本进行编译.

在jetpack compose中将图像添加到脚手架顶部栏

Kotlin Compose forEach 中的负间距

WindowManager 内的 RecyclerView 不更新

如何在 Kotlin 的片段中制作图像列表?