如何在android中实现两个同步视图之间的滑入和滑出动画

Dav*_*him 16 android android-jetpack-compose

我知道我可以使用AnimatedVisibilityComposable 函数并实现可见性动画的滑入动画,但我想要实现的是当一个布局处于进入动画而另一个处于退出动画时,类似于下图。

注意:我知道我应该为不同的屏幕使用导航组合,并且目的地之间的动画仍在开发中,但我想在屏幕的一部分内容上实现这一点,类似于 CrossFade 动画。

在此输入图像描述

ngl*_*ber 14

正如您所提到的,该动画应该由导航库实现,并且有一张针对该动画的票证

考虑到这一点,我将我的答案留在这里,希望它有所帮助......

我将把它分成三个部分:

  1. 容器:
@Composable
fun SlideInAnimationScreen() {
    // I'm using the same duration for all animations. 
    val animationTime = 300 

    // This state is controlling if the second screen is being displayed or not
    var showScreen2 by remember { mutableStateOf(false) }

    // This is just to give that dark effect when the first screen is closed...
    val color = animateColorAsState(
        targetValue = if (showScreen2) Color.DarkGray else Color.Red,
        animationSpec = tween(
            durationMillis = animationTime,
            easing = LinearEasing
        )
    )
    Box(Modifier.fillMaxSize()) {
       // Both Screen1 and Screen2 are declared here...
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 第一个屏幕只需做一个小幻灯片即可创建视差效果。我还将背景颜色从红色更改为深色,只是为了提供重叠/隐藏/深色效果。
// Screen 1
AnimatedVisibility(
    !showScreen2,
    modifier = Modifier.fillMaxSize(),
    enter = slideInHorizontally(
        initialOffsetX = { -300 }, // small slide 300px
        animationSpec = tween(
            durationMillis = animationTime, 
            easing = LinearEasing // interpolator
        )
    ),
    exit = slideOutHorizontally(
        targetOffsetX = { -300 }, =
        animationSpec = tween(
            durationMillis = animationTime, 
            easing = LinearEasing
        )
    )
) {
    Box(
        Modifier
            .fillMaxSize()
            .background(color.value) // animating the color
    ) {
        Button(modifier = Modifier.align(Alignment.Center),
            onClick = {
                showScreen2 = true
            }) {
            Text(text = "Ok")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 第二个确实是从边缘滑落。
// Screen 2
AnimatedVisibility(
    showScreen2,
    modifier = Modifier.fillMaxSize(),
    enter = slideInHorizontally(
        initialOffsetX = { it }, // it == fullWidth
        animationSpec = tween(
            durationMillis = animationTime, 
            easing = LinearEasing
        )
    ),
    exit = slideOutHorizontally(
        targetOffsetX = { it },
        animationSpec = tween(
            durationMillis = animationTime, 
            easing = LinearEasing
        )
    )
) {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Blue)
    ) {
        Button(modifier = Modifier.align(Alignment.Center),
            onClick = {
                showScreen2 = false
            }) {
            Text(text = "Back")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

在此输入图像描述

  • 我们能否将您的解决方案重构为支持多个屏幕的更通用的解决方案,类似于 CrossFade? (2认同)

Dav*_*him 5

在深入研究 CrossFade 的代码后,我为十字滑动实现了一个类似的代码,它在按下 backButton 时启用反向动画

这是: https: //gist.github.com/DavidIbrahim/5f4c0387b571f657f4de976822c2a225

使用示例

@Composable
fun CrossSlideExample(){
    var currentPage by remember { mutableStateOf("A") }
    CrossSlide(targetState = currentPage, reverseAnimation: Boolean = false) { screen ->
        when (screen) {
            "A" -> Text("Page A")
            "B" -> Text("Page B")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)