compose自定义布局和动画的结合-摩天轮效果

简介: compose自定义布局和动画的结合-摩天轮效果

先看最终效果效果


image.png


Layout作用


自定义布局使用Layout实现,Layout可以布局多个可组合项。我们可以通过Layout实现各种复杂的自定义布局。ColumnRow都是通过Layout实现的


Layout api讲解


下面的代码摘抄自官方,实现了一个Column的效果

@Composable
fun MyBasicColumn(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Layout(
        modifier = modifier,
        content = content
    ) { measurables, constraints ->
      //placeables是测量完的子view列表
       val placeables = measurables.map { measurable ->
            measurable.measure(constraints)//根据父布局约束测量
        }
        layout(constraints.maxWidth, constraints.maxHeight) {//maxWidth就是父布局的最大宽度,layout函数是用来布局摆放子布局的
            var yPosition = 0
            placeables.forEach { placeable ->
                placeable.placeRelative(x = 0, y = yPosition)//根据相对位置摆放子view
                yPosition += placeable.height
            }
        }
    }
}
复制代码
  • content: 被传递给子项的view函数
  • measurables: 所有可被测量的布局列表
  • constraints: 来自于父布局的约束条件


实现自定义布局


本例中我们实现了这样一个效果,传入n个子布局,然后将这个子布局使用自定义布局Layout实现原型摆放的效果。代码如下

@Composable
private fun startAnimLayoutReal(
    modifier: Modifier = Modifier,
    degree: Double,
    content: @Composable () -> Unit
) {
    Layout(content = content, modifier = modifier) { measurable, constraint ->
        val placeable = measurable.map {
            it.measure(constraint)
        }
        val perDegree = 2 * Math.PI / placeable.size//两个子view之间的弧度间隔
        val width = 300//摆放大圆的半径
        val startX = 450//圆心x坐标
        val startY = 450//圆心y坐标
        var currentDegree = degree//当前所属的弧度
        layout(constraint.maxWidth, constraint.maxHeight) {
            placeable.forEach {
                val x = Math.sin(currentDegree) * width + startY
                val y = Math.cos(currentDegree) * width + startX
                it.placeRelative(x = x.toInt(), y = y.toInt())//根据控件当前弧度将控件摆放在大圆的对应位置上
                currentDegree += perDegree.toFloat()//弧度加一,摆放下一个子布局
            }
        }
    }
}
复制代码


给布局加上摩天轮的旋转效果

我们使用rememberInfiniteTransition实现动画无限执行的效果,这样多个子view围绕之圆心进行无限旋转,看起来就像一个大摩天轮

@Composable
fun starLayout() {
    val size = 30.dp
    Column {
        buildTopBar(title = "摩天轮")
        startLayoutReal {
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
            Image(
                modifier = Modifier.size(size),
                painter = painterResource(id = R.drawable.apple),
                contentDescription = ""
            )
        }
    }
}
@Composable
private fun startLayoutReal(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
    val transition = rememberInfiniteTransition()
    val currentDegree by transition.animateFloat(
        initialValue = 0f, targetValue = 2 * Math.PI.toFloat(), animationSpec = infiniteRepeatable(
            animation = tween(10 * 1000, easing = LinearEasing),
            repeatMode = RepeatMode.Restart
        )
    )
    startAnimLayoutReal(modifier = modifier, currentDegree.toDouble(), content = content)
}
@Composable
private fun startAnimLayoutReal(
    modifier: Modifier = Modifier,
    degree: Double,
    content: @Composable () -> Unit
) {
    Layout(content = content, modifier = modifier) { measurable, constraint ->
        val placeable = measurable.map {
            it.measure(constraint)
        }
        val perDegree = 2 * Math.PI / placeable.size//两个子view之间的弧度间隔
        val width = 300//摆放大圆的半径
        val startX = 450//圆心x坐标
        val startY = 450//圆心y坐标
        var currentDegree = degree//当前所属的弧度
        layout(constraint.maxWidth, constraint.maxHeight) {
            placeable.forEach {
                val x = Math.sin(currentDegree) * width + startY
                val y = Math.cos(currentDegree) * width + startX
                it.placeRelative(x = x.toInt(), y = y.toInt())//根据控件当前弧度将控件摆放在大圆的对应位置上
                currentDegree += perDegree.toFloat()//弧度加一,摆放下一个子布局
            }
        }
    }
}



相关文章
|
Java Shell 网络安全
springboot 远程调用shell脚本,环境为windows
本文是博主学习SpringBoot的记录,希望对大家有所帮助。
1363 0
springboot 远程调用shell脚本,环境为windows
|
编解码 Android开发
Android 常用布局单位区别(dp、sp、px、pt、in、mm)
Android 常用布局单位区别(dp、sp、px、pt、in、mm)
1939 0
|
机器学习/深度学习 运维 算法
梯度&散度&旋度&峰度&偏度你分得清楚吗?驻点&鞍点你分得清楚吗?曲率&斜率你分得清楚吗?
本文介绍了四种常见的物理量:加速度,速度,位移和力学功。详细介绍了它们的定义、计算以及在物理学和工程学领域中的应用。此外,本文还介绍了四种与物理量相关的概念:向量、标量、质量和密度。 数学,物理,机器学习领域常见概念区分
4108 0
|
3月前
|
人工智能 弹性计算 搜索推荐
开源 OpenClaw 实战:30 分钟在阿里云部署你的第一个 AI Agent
阿里云推出OpenClaw一键部署方案,仅需9.9元即可在轻量应用服务器、无影云电脑或ECS上快速搭建本地优先AI助理。三步完成:选环境→一键安装配置(集成百炼API)→个性化任务分配,零代码轻松启用智能体。
561 4
Jetpack Compose中ViewModel、Flow、Hilt、Coil的使用
Jetpack Compose中ViewModel、Flow、Hilt、Coil的使用
2065 0
Jetpack Compose中ViewModel、Flow、Hilt、Coil的使用
|
Arthas 测试技术 网络安全
The telnet port 3658 is used by process
是否在本地使用Arthas的时候,遇到The telnet port 3658 is used by process 34725 instead of target process 44848, you will connect to an unexpected process的异常,其实解决方法很简单。
2757 0
The telnet port 3658 is used by process
|
缓存 Java 数据库
Android的ANR原理
【10月更文挑战第18天】了解 ANR 的原理对于开发高质量的 Android 应用至关重要。通过合理的设计和优化,可以有效避免 ANR 的发生,提升应用的性能和用户体验。
833 56
|
机器学习/深度学习 自然语言处理 PyTorch
精通 Transformers(一)(2)
精通 Transformers(一)
721 4
|
机器学习/深度学习 算法 安全
从方向导数到梯度:深度学习中的关键数学概念详解
方向导数衡量函数在特定方向上的变化率,其值可通过梯度与方向向量的点积或构造辅助函数求得。梯度则是由偏导数组成的向量,指向函数值增长最快的方向,其模长等于最速上升方向上的方向导数。这两者的关系在多维函数分析中至关重要,广泛应用于优化算法等领域。
2226 36
从方向导数到梯度:深度学习中的关键数学概念详解
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
1076 19