使用Compose创造有趣的动画:动态的艺术(1)

187 阅读1分钟

前言

本人所有文章中的compose默认指的是compose multiplatform,所以给出的动画效果理论上可以在desktop、android、ios和web上运行,如果特指Android的jetpack compose会单独说明。

背景

上班无聊打开稀土掘金,看到掘友们写出了很多了有意思的效果,所以就想模仿一下。

1.折叠手风琴效果

gif.gif

@Composable
fun AccordionItem(
    painter: Painter,
    isSelected: Boolean,
    onClick: () -> Unit
) {
    val width by animateDpAsState(
        targetValue = if (isSelected) 300.dp else 100.dp,
        animationSpec = tween(1000, easing = FastOutSlowInEasing)
    )
    val background by animateColorAsState(
        targetValue = if (isSelected) Color.LightGray else Color.Gray,
        animationSpec = tween(1000, easing = FastOutSlowInEasing)
    )

    Box(
        modifier = Modifier
            .padding(8.dp)
            .width(width)
            .height(200.dp)
            .clip(RoundedCornerShape(16.dp))
            .clickable { onClick() }
            .background(background)
    ) {
        Image(
            painter = painter,
            contentDescription = null,
            modifier = Modifier.fillMaxSize()
        )
    }
}


@Composable
fun AccordionList(painterList: List<DrawableResource>) {
    var selectedIndex by remember { mutableStateOf(1) }

    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.Center
    ) {
        painterList.forEachIndexed { index, painter ->
            AccordionItem(
                painter = painterResource(painter),
                isSelected = index == selectedIndex,
                onClick = { selectedIndex = if (selectedIndex == index) -1 else index }
            )
        }
    }
}

@Composable
fun AccordionScreen() {
    val imageList = listOf(
        Res.drawable.tree1,
        Res.drawable.tree2,
        Res.drawable.tree3,
        Res.drawable.tree4
    )

    MaterialTheme {
        Surface {
            AccordionList(painterList = imageList)
        }
    }
}

2.数字增长效果

gif.gif

@Composable
fun AnimatedCounter(targetValue: Int) {
    // 使用 animateIntAsState 创建一个动画状态
    val animatedValue by animateIntAsState(
        targetValue = targetValue,
        animationSpec = tween(
            durationMillis = 1000,
            easing = FastOutSlowInEasing
        )
    )

    // 显示动画化的数字
    Text(
        text = "$animatedValue",
        style = MaterialTheme.typography.h3.copy(fontSize = 50.sp)
    )
}

@Composable
fun CounterScreen() {
    var counter by remember { mutableIntStateOf(0) }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        AnimatedCounter(targetValue = counter)

        Spacer(modifier = Modifier.height(16.dp))

        Button(onClick = { counter += (1..10000).random() }) {
            Text("Increase")
        }
    }
}

compose实现数字增长很简单,只需要修改这个可变数字,再使用 animateIntAsState 创建一个动画状态,就可以实现。