我对喷气背包完全是新手.我正在做一个项目,其中一个形状是围绕特定半径的中心点旋转的.单击按钮后,图形需要开始在比以前更小的半径内旋转.我能够实现那个比特,但当形状切换时,它会暂时停止,以垂直线的方式切换到较小半径的路径,然后再次开始旋转,这给它带来了一种糟糕的外观.我如何才能使形状的这种切换/过渡变得顺畅?以下是我使用的代码:

@Composable
fun AnimateObject(){
    val transition = rememberInfiniteTransition()
    val animatedProgress = transition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = keyframes {
                durationMillis = 3000
                0.0f at 0 with LinearEasing
                1.0f at 3000 with LinearEasing
            },
            repeatMode = RepeatMode.Restart
        )
    )

    val outerCircleRadius = 450f
    val innerCircleRadius = 250f
    var outerCircleCenter = Offset(x = 0f, y = 0f)
    var innerCircleCenter = Offset(x = 0f, y = 0f)
    var playerXOffset = remember { mutableStateOf(0f) }
    var playerYOffset = remember { mutableStateOf(0f) }
    var isInOuterCircle = remember { mutableStateOf(true) }



    val angle = animatedProgress.value * 360f
    val radians = Math.toRadians(angle.toDouble())

    Canvas(modifier = Modifier.size(200.dp), onDraw = {

        outerCircleCenter = Offset(size.width / 2, size.height / 2)
        innerCircleCenter = Offset(size.width / 2, size.height / 2)

        CreateCirlcePath(radius = outerCircleRadius, center = outerCircleCenter, drawScope = this)
        CreateCirlcePath(radius = innerCircleRadius, center = innerCircleCenter, drawScope = this)

        if (isInOuterCircle.value == true) {
            playerXOffset.value = outerCircleCenter.x + outerCircleRadius * cos(radians).toFloat()
            playerYOffset.value = outerCircleCenter.y + outerCircleRadius * sin(radians).toFloat()
        } else {
            playerXOffset.value = innerCircleCenter.x + innerCircleRadius * Math.cos(radians).toFloat()
            playerYOffset.value = innerCircleCenter.y + innerCircleRadius * Math.sin(radians).toFloat()
        }


        print("Offset values, ${playerXOffset.value} ")

        // Draw the moving shape (circle in this case)
        drawCircle(
            color = Color.Blue,
            center = Offset(playerXOffset.value, playerYOffset.value),
            radius = 16.dp.toPx()
        )
    })

    Row {
        val buttonTitle = remember { mutableStateOf("Click Me") }
        Button(
            onClick = {
                buttonTitle.value = "Clicked"
                isInOuterCircle.value = !isInOuterCircle.value
            },
            modifier = Modifier.size(width = 150.dp, height = 50.dp)
        ) {
            Text(text = buttonTitle.value)
        }
    }
}

我正经历着从一条环路到另一条环路的短暂过渡.以下是演示其外观的链接:

https://imgur.com/a/M6GDfcX

我希望这个过渡是平滑的,当从一个圆过渡到另一个圆时,图形继续其运动,在切换过程中,它以倾斜的方式(或像切线一样)落在另一个圆的路径上. 如有任何帮助,我们将不胜感激!谢谢

推荐答案

您可以使用动画在内圆和外圆之间进行线性插补.

https://en.wikipedia.org/wiki/Linear_interpolation

我使用了画布的旋转功能,只对圆的半径和结果进行了插补

enter image description here

@Preview
@Composable
private fun RadiusChangeLerpAnimationTes() {

    val outerCircleRadius = 450f
    val innerCircleRadius = 250f

    var isOut by remember {
        mutableStateOf(false)
    }

    val transition = rememberInfiniteTransition(label = "")

    val angle by transition.animateFloat(
        initialValue = 0f,
        targetValue = 360f,
        animationSpec = infiniteRepeatable(
            animation = keyframes {
                durationMillis = 3000
                0.0f at 0 with LinearEasing
                360f at 3000 with LinearEasing
            },
            repeatMode = RepeatMode.Restart
        ), label = ""
    )

    val progress by animateFloatAsState(
        if (isOut) 1f else 0f,
        animationSpec = tween(durationMillis = 700, easing = LinearEasing),
        label = "distance"
    )

    val distance = remember(progress) {
        lerp(innerCircleRadius, outerCircleRadius, progress)
    }

    var position by remember {
        mutableStateOf(Offset.Unspecified)
    }

    Column {
        Canvas(
            modifier = Modifier.fillMaxWidth().aspectRatio(1f)
        ) {

            drawCircle(
                color = Color.Blue,
                radius = outerCircleRadius,
                style = Stroke(2.dp.toPx())
            )

            drawCircle(
                color = Color.Blue,
                radius = innerCircleRadius,
                style = Stroke(2.dp.toPx())
            )

            rotate(angle) {
                drawCircle(
                    color = Color.Red,
                    radius = 50f,
                    center = Offset(center.x + distance, center.y)

                )
            }

            val angleInRadians = angle * DEGREE_TO_RAD
            position = Offset(
                center.x + distance * cos(angleInRadians), center.y + distance * sin(angleInRadians)
            )
        }

        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = {
                isOut = isOut.not()
            }
        ) {
            Text("Out $isOut")
        }

        if (position != Offset.Unspecified) {
            Text("Position: $position")
        }
    }
}

private const val DEGREE_TO_RAD = (Math.PI / 180f).toFloat()

Android相关问答推荐

使用Kotlin的SD卡

AdMob:MobileAds. initialize()—java. lang. xml对于某些设备不能强制转换为java. lang. String""

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

如何将子零部件的大小调整为可以调整大小的父组件大小?

Android从已连接的设备获得GATT

使用Jetpack Compose创建特定于电视的布局

如何在喷气背包中绕过集装箱

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

Kotlin - 在继续之前如何等待这个协程完成?

如何将DrawableId参数传递给XML布局?

Android 访问任意公共目录

Android:使用依赖项 ViewModelProviderFactory 初始化 ViewModel 的正确方法

在一个函数中组合相同的流 struct

从 Jetpack Compose 中的 IconButton 中删除黑色色调

Jetpack compose :使用 rememberSaveable 时未应用待处理的合成

如何正确地将图像上传到 Jetpack Compose 中的 LazyList 中的项目?

在事件中使用 Context/Toast 时不需要的重组 - Jetpack Compose

自定义 Compose Arrangement 以在 LazyRow/LazyColumn 的开头和结尾添加额外的间距

新的内部测试应用程序版本不适用于测试人员,即使它说它们是

Unity:Android 上随机接近零的 FPS 下降(提供了很多线索)