四时宝库

程序员的知识宝库

在 Android 中使用 Compose 构建创意动画1

第一节-Jetpack Compose 中的自定义动画处理程序

通过自定义动画拥抱动态交互

在本节中,我们将探讨如何使用 Jetpack Compose 中的高级自定义动画处理程序来创建动态和交互式 UI 元素。该示例演示了用户交互如何以有意义的方式影响动画。

示例 - 互动游戏角色运动

我们将通过一个示例来说明这个概念,游戏中的人物(由面部图标表示)会按照用户拖动控制点的路径来确定人物的移动路径。

@Composable
fun GameCharacterMovement() {
    val startPosition = Offset(100f, 100f)
    val endPosition = Offset(250f, 400f)
    val controlPoint = remember { mutableStateOf(Offset(200f, 300f)) }
    val position = remember { Animatable(startPosition, Offset.VectorConverter) }

    LaunchedEffect(controlPoint.value) {
        position.animateTo(
            targetValue = endPosition,
            animationSpec = keyframes {
                durationMillis = 5000
                controlPoint.value at 2500 // midway point controlled by the draggable control point
            }
        )
    }

    val onControlPointChange: (offset: Offset) -> Unit = {
        controlPoint.value = it
    }

    Box(modifier = Modifier.fillMaxSize()) {

        Icon(
            Icons.Filled.Face, contentDescription = "Localized description", modifier = Modifier
                .size(50.dp)
                .offset(x = position.value.x.dp, y = position.value.y.dp)
        )

        DraggableControlPoint(controlPoint.value, onControlPointChange)
    }
}
  • GameCharacterMovement为游戏角色的图标设置动画。动画路径由controlPoint控制,用于用户交互设置和更新。
  • Animatable用于将图标的位置从 startPosition平滑过渡到endPosition
  • LaunchedEffect监听controlPoint值的变化,每当控制点移动时重新触发动画。
  • animationSpec它是定义动画的持续时间、延迟和缓动的配置。它确定动画值如何随时间变化。
  • keyframes— 允许在动画期间指定特定的时间值,从而能够控制动画的中间点。它对于创建复杂的、精心设计的动画特别有用。
  • keyframes块将动画定义为关键帧序列。在 2500 毫秒(中间点)时,角色到达控制点,然后继续到达结束位置。
Composable
fun DraggableControlPoint(controlPoint: Offset, onControlPointChange: (Offset) -> Unit) {
    var localPosition by remember { mutableStateOf(controlPoint) }
    Box(
        modifier = Modifier
            .offset {
                IntOffset(
                    x = localPosition.x.roundToInt() - 15,
                    y = localPosition.y.roundToInt() - 15
                )
            }
            .size(30.dp)
            .background(Color.Red, shape = CircleShape)
            .pointerInput(Unit) {
                detectDragGestures(onDragEnd = {
                    onControlPointChange(localPosition)
                }) { _, dragAmount ->
                    // adjust based on screen bounds
                    val newX = (localPosition.x + dragAmount.x).coerceIn(0f, 600f)
                    val newY = (localPosition.y + dragAmount.y).coerceIn(0f, 600f)
                    localPosition = Offset(newX, newY)
                }
            }
    )
}

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接