我想要两个合成开始,并同时播放他们的动画.例如,这是我的设置:

    LazyColumn(
        .semantics(mergeDescendants = true) { contentDescription = contentDes }
    ) {

        item { 
            ShimmeringComposable() // takes up a lot of the page
        } 
   
        item {
            Spacer()
        }
 
        item {
            ShimmeringComposable() // under the fold (off the screen)
        }
    }

我注意到,大多数时候,第一个合成体的动画首先开始播放,然后第二个合成体的动画开始播放.如果第一个可合成的内容在布局中可见,而第二个可合成的内容在屏幕外,有时也会发生这种情况.

有没有办法让两者同步,让它们同时开始/播放动画?

此代码基于YouTube视频教程中的代码:https://www.youtube.com/watch?v=NyO99OJPPec

@Composable
fun ShimmeringComposable() {
    Box(Modifier
        .size(50.dp)
        .shimmer()
    )
}
fun Modifier.shimmer(): Modifier = composed {
    var size by remember {
        mutableStateOf(IntSize.Zero)
    }
    val width = size.width.toFloat()
    val height = size.height.toFloat()
    val transition = rememberInfiniteTransition()
    val startOffsetX by transition.animateFloat(
        initialValue = -2 * width, 
        targetValue = 2 * width,
        animationSpec = infiniteRepeatable(
            animation = tween(
                durationMillis = 1000,
            )
        )
    )
 

    background(
        brush = Brush.linearGradient(
            colors = listOf(Color.gray,Color.white,Color.gray),
            start = Offset(startOffsetX, 0),
            end = Offset(startOffsetX + width, height)
        )
    ).onGloballyPositioned { size = it.size }
}

更新:为清晰起见添加了更多代码

编辑:我想我知道问题出在哪里了.对于InfiniteTransition,动画从合成开始,LazyColumn将合成屏幕上可见的项目.然而,对于屏幕外的那些,直到它们进入视线(用户向下滚动)才会被合成.将所有闪闪发光的元素都包装在Column英寸中可能会缓解这一问题,因为只要你不使用大量闪闪发光的合成material 作为柱子,就不会像LazyColumn那样具有表现力.

推荐答案

您可以将进度作为参数提供给每个可合成组件,同时通过一个动画集中控制进度更改.这样,即使合成体一个接一个地进入合成,它也会以相同的进度设置动画.

enter image description here

您可以通过绘制修改器使用DrawScope获得尺寸,而不是Modifier.loballyPosited.

fun Modifier.newShimmer(progress: Float) = this.then(

    Modifier
        .drawWithContent {

            val width = size.width
            val height = size.height
            val offset = progress * width

            drawContent()
            val brush = Brush.linearGradient(
                colors = listOf(Color.Gray, Color.White, Color.Gray),
                start = Offset(offset, 0f),
                end = Offset(offset + width, height)
            )
            drawRect(brush)
        }
)

并将进展传递给Composable

@Composable
fun ShimmerView(progress: Float) {
    Box(
        Modifier
            .size(80.dp)
            .newShimmer(progress = progress)
    )
}


    val transition = rememberInfiniteTransition(label = "shimmer")
    val startOffsetX by transition.animateFloat(
        initialValue = -2f,
        targetValue = 2f,
        animationSpec = infiniteRepeatable(
            animation = tween(
                durationMillis = 3000,
            )
        ), label = "shimmer"
    )

    Text(text = "NEW STYLE")
    ShimmerView(progress = startOffsetX)
    Spacer(Modifier.height(20.dp))
    ShimmerView(progress = startOffsetX)

完整代码

@Preview
@Composable
private fun ShimmerTest() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(20.dp)
    ) {


        var showItem by remember {
            mutableStateOf(false)
        }

        Text(text = "OLD STYLE")
        ShimmeringComposable() // first composable

        Spacer(Modifier.height(20.dp))

        ShimmeringComposable() // second composable

        Spacer(Modifier.height(20.dp))
        if (showItem) {
            ShimmeringComposable()
        }

        Spacer(Modifier.height(20.dp))

        val transition = rememberInfiniteTransition(label = "shimmer")
        val startOffsetX by transition.animateFloat(
            initialValue = -2f,
            targetValue = 2f,
            animationSpec = infiniteRepeatable(
                animation = tween(
                    durationMillis = 3000,
                )
            ), label = "shimmer"
        )

        Text(text = "NEW STYLE")
        ShimmerView(progress = startOffsetX)
        Spacer(Modifier.height(20.dp))
        ShimmerView(progress = startOffsetX)
        Spacer(Modifier.height(20.dp))
        if (showItem) {
            ShimmerView(progress = startOffsetX)
        }

        Button(onClick = { showItem = showItem.not() }) {
            Text(text = "Show item: $showItem")
        }

    }
}

@Composable
fun ShimmerView(progress: Float) {
    Box(
        Modifier
            .size(80.dp)
            .newShimmer(progress = progress)
    )
}

@Composable
fun ShimmeringComposable() {
    Box(
        Modifier
            .size(80.dp)
            .shimmer()
    )
}

fun Modifier.newShimmer(progress: Float) = this.then(

    Modifier
        .drawWithContent {

            val width = size.width
            val height = size.height
            val offset = progress * width

            drawContent()
            val brush = Brush.linearGradient(
                colors = listOf(Color.Gray, Color.White, Color.Gray),
                start = Offset(offset, 0f),
                end = Offset(offset + width, height)
            )
            drawRect(brush)
        }
)

fun Modifier.shimmer(): Modifier = composed {
    var size by remember {
        mutableStateOf(IntSize.Zero)
    }
    val width = size.width.toFloat()
    val height = size.height.toFloat()
    val transition = rememberInfiniteTransition(label = "shimmer")
    val startOffsetX by transition.animateFloat(
        initialValue = -2 * width,
        targetValue = 2 * width,
        animationSpec = infiniteRepeatable(
            animation = tween(
                durationMillis = 3000,
            )
        ), label = "shimmer"
    )

    Modifier
        .background(
            brush = Brush.linearGradient(
                colors = listOf(Color.Gray, Color.White, Color.Gray),
                start = Offset(startOffsetX, 0f),
                end = Offset(startOffsetX + width, height)
            )
        )
        .onGloballyPositioned { size = it.size }
}

Android相关问答推荐

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

Android Kotlin DSL Gradle找不到自定义存储库中的依赖项

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

在Android Studio中,如何在BuildSrc Dependenices Kotlin文件中指定时标记与旧版本的依赖关系

设置文本 colored颜色 动画时如何减少重新组合?

未解析的引用:视图模型

为什么 Android Compose 将片段作为参数传递给 Composables 函数?

Android Kotlin - 计费 - 从应用内购买获取productId

Compose 状态不是 recomposing

系统导航栏在某些场景下应用了深色效果

用作输入参数的 Lambda 函数导致重组

Android CompanionDeviceManager 永远找不到任何附近的蓝牙设备

如何在 Jetpack Compose 中禁用 Horizo​​ntalPager 的分页动画

如何在行/列/卡片 compose 中添加左边框

如何在 TextButton 中分隔文本和图标

如何在 Jetpack Compose 中擦除画布时变得透明,现在我得到白色?

为什么使用 React Native 和 expo 创建的 APK 体积这么大?

如何让用户与任意应用程序共享文件?

如何满足设备内框架的无效 Wear OS 屏幕截图Wear OS 表盘策略违规?

OpenGLES,为什么 glReadPixels() 不能从 FBO 的 Renderbuffer 的 colored颜色 缓冲区中读取数据?