【问题标题】:Animating content in Jetpack ComposeJetpack Compose 中的动画内容
【发布时间】:2021-10-11 04:38:05
【问题描述】:

我想为两个状态之间的几个 Composable 设置动画,基本上从 Row 更改为 Column。在视图系统中,我会将这些放在ConstraintLayout 中,然后根据我要使用的布局更新约束——在 Jetpack Compose 上执行此操作的等效方法是什么?我也可以定义一个ConstraintLayout,但我对不依赖于它的解决方案感兴趣。

这是我尝试过的,但它不会为视图位置设置动画,它只是将一个淡出并淡入另一个。我知道每个状态的 2 个可组合项之间必须存在某种联系,以便它们可以动画化,但我不知道如何实现。

enum class ContentState {
    One,
    Two,
}

@ExperimentalAnimationApi
@Composable
fun ContentAnimator(
    modifier: Modifier = Modifier,
    state: ContentState = ContentState.One,
) {
    Box(
        modifier = modifier,
        contentAlignment = Alignment.Center,
    ) {
        AnimatedContent(
            targetState = state,
        ) { targetState ->
            when (targetState) {
                ContentState.One -> OneLayout()
                ContentState.Two -> TwoLayout()
            }
        }
    }
}

@Composable
fun OneLayout() {
    Row(
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Box(
            modifier = Modifier
                .size(width = 48.dp, height = 48.dp)
                .background(Color.Red),
        )
        Spacer(modifier = Modifier.width(16.dp))
        Text(
            text = "Sample text",
            style = MaterialTheme.typography.h3,
        )
    }
}

@Composable
fun TwoLayout() {
    Column(
        modifier = Modifier.fillMaxWidth(),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Box(
            modifier = Modifier
                .size(width = 48.dp, height = 48.dp)
                .background(Color.Red)
        )
        Spacer(modifier = Modifier.height(8.dp))
        Text(
            text = "Sample text",
            style = MaterialTheme.typography.h3,
        )
    }
}

我想在下面显示的这两种状态之间来回切换。我认为另一种选择是使用Layoutanimatable 对象,然后根据animatable 手动计算这两个对象的位置,但这似乎是一个非常低级的解决方案。

【问题讨论】:

  • 要为对象设置动画,它必须是 Compose 树中完全相同的对象,并且在您的代码中,您可以为不同的布局创建不同的视图。 `ConstraintLayout' 之所以有效,是因为通过更改约束您正在移动相同的视图,而不是创建新视图。请参阅Demystify SwiftUI:它讨论了一个不同的声明式 UI 框架,但在 Compose 中,出于相同的原因,它的工作方式完全相同。
  • 谢谢,我明白了,但是除了使用 ConstraintLayout 或手动移动布局中的视图之外,还有其他方法吗?这就是我要问的。
  • @Philip,我想我不同意这一点。 Here 是一个使用两个不同视图的示例,但如果您定义自定义 transitionSpec,它就可以正常工作。只需在他们解释SizeTransform(可组合?)的部分向下滚动一下即可
  • 哦,这是可组合而不是视图
  • AnimatedContent 也是我想到的第一个地方,但我认为在不必要的时候使用这些 API 是没有必要的。为什么不能只使用 animateDpAsState 为自定义 Composable 中的 Offset 设置动画? AnimatedContent 不支持单独为子可组合项设置动画,因此使其工作有点复杂。试试另一种方法,或者如果您需要一些样品或其他东西,请告诉我们

标签: android android-jetpack-compose


【解决方案1】:

好的,这是一个非常简单的实现,但它就像一个魅力。另外,没有ConstraintLayout

@Composable
fun Sample(state: AlignmentState){
    //Dimensions of the static/stable box
    val redWidth = 50
    val redHeight = 50
    
    //Animated Coordinates of the dynamic box
    val blueX by animateDpAsState(targetValue = (if (state == AlignmentState.Rowed) (redWidth * 1.25f).roundToInt() else 0).dp )
    val blueY by animateDpAsState(targetValue = (if (state == AlignmentState.Rowed) 0 else redHeight).dp)
    
    Layout(content = {
        Box(
            modifier = Modifier
                .height(redWidth.dp)
                .width(redHeight.dp)
                .background(Color.Red)
        )
        Box(
            modifier = Modifier
                .height(50.dp)
                .width(50.dp)
                .background(Color.Red)
        )
    }) { measurables, constraints ->
        val red = measurables[0].measure(constraints)
        val blue = measurables[1].measure(constraints)
        
        layout(constraints.maxWidth, constraints.maxHeight) {
            red.place(0, 0)
            blue.place(blueX.value.roundToInt(), blueY.value.roundToInt())
        }
        
    }

}

您可能希望将 animateDpAsState 替换为 animateIntAsState 以避免上面的所有样板。无论如何,这假设您知道 s=fixed 框的尺寸,但您知道,只需根据您的用例进行更改即可。

【讨论】:

  • 创建AlignmentState 枚举不会有问题,所以我跳过了它
猜你喜欢
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-22
相关资源
最近更新 更多