Jetpack Compose 动画(高级动画示例:手势)

43 阅读1分钟

与单独处理动画相比,当我们处理触摸事件和动画时,必须考虑几个事项。首先,当触摸事件开始时,我们可能需要中断正在播放的动画,因为用户互动应当具有最高优先级。

在下面的示例中,我们使用 Animatable 表示圆形组件的偏移位置。触摸事件由 [pointerInput] 修饰符处理。当检测到新的点按事件时,我们将调用 animateTo 以将偏移值通过动画过渡到点按位置。在动画播放期间也可能发生点按事件。在这种情况下,animateTo 会中断正在播放的动画,启动动画以过渡到新的目标位置,同时保持被中断的动画的速度。

package com.lujianfei.composeui.page.animation

import MyTopAppBar
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlin.math.roundToInt


/**
 * Author: lujianfei
 * Date: 2024/3/27 11:25
 * Description:
 */

@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun AnimationGesturePage(navController: NavHostController?= null) {
    val offset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) }

    Scaffold(
        topBar = {
            MyTopAppBar(
                title = {
                    Text("高级动画示例:手势")
                },
                navigationIcon = {
                    IconButton(onClick = { navController?.popBackStack() }) {
                        Icon(Icons.Filled.ArrowBack,"")
                    }
                }
            )
        },
    ) { padding ->
        Box(
            modifier = Modifier.padding(padding)
                .fillMaxSize()
                .pointerInput(Unit) {
                    coroutineScope {
                        while (true) {
                            // Detect a tap event and obtain its position.
                            awaitPointerEventScope {
                                val position = awaitFirstDown().position
                                launch {
                                    // Animate to the tap position.
                                    offset.animateTo(position)
                                }
                            }
                        }
                    }
                }
        ) {
            Box(modifier = Modifier.offset { offset.value.toIntOffset() }.size(50.dp).background(Color.Black))
        }
    }
}

private fun Offset.toIntOffset() = IntOffset(x.roundToInt(), y.roundToInt())

上一篇 Jetpack Compose 动画(基于动画矢量图像)

下一篇 Jetpack Compose 动画(自定义动画)