Android中分析Jetpack Compose动画内部的实现原理

目录
  • 前言
  • 正文
  • 总结

前言

Compose的动画Api用起来很简单,效果看起来很神奇,那么它内部到底是如何运转的呢?

使用动画的代码示例:

var isOffset by remember { mutableStateOf(false) }
val offsetAnimation by animateDpAsState(targetValue = if (isOffset) 100.dp else 0.dp)
Button(
    onClick = { isOffset = !isOffset },
    modifier = Modifier.offset(0.dp, offsetAnimation)
) {
    Text(text = "点我进行位移")
}

看到有一个Boolean类型的isOffset状态,控制着offsetAnimation动画,然后动画又控制着Button的offset,最终实现了动画效果

正文

我们主要就看一下animateDpAsState(animate*AsState)做了什么

跟一下animateDpAsState最后会走进animateValueAsState方法中:

方法内部创建了一个Animatable动画类

然后我们跟着上图的箭头看,在targetValue发生变化后,会通过channel来发送targetValue值的变化,然后launch启动一个协程,并在其中调用了animatable的animateTo方法

接着我们就看看Animatable类是如何做动画的:

主要就是内部持有一个AnimationState类型(State)的internalState 变量,然后我们接着上面的代码跟一下animateTo方法:

没什么好说的,包了一下targetValue,接着就调用了runAnimation方法,接着往下跟(截不下分成两张图):

主要逻辑就是endState.animate()
endState就是copy的Animatable中的AnimationState对象internalState,也就是动画的初始值

然后animation就是在animateTo方法中包装了动画目标值的对象

接着跟animate方法:

这个方法主要分为两部分,第一部分就是构建了一个AnimationScope,一个数据结构,用来存放动画需要的一些信息

第二个部分就是真正动画计算和生效的地方,doAnimationFrame

首先会在第一次创建AnimationScope的时候执行一次(或再一下帧执行一次,通过callWithFrameNanos方法)

然后会判断如果动画还未执行完毕,就一直循环(while),一帧一帧执行doAnimationFrame计算动画的值

doAnimationFrame方法代码:

其中通过时间等参数计算当前动画应该设置的值,包括lastFrameTimeNanos和value等属性,然后再最后调用updateState方法去将AnimationScope的值更新到AnimationState中

updatState方法代码:

这个state对象其实也就是animateDpAsState中的Animatable动画类中的AnimationState对象internalState

所以上面其实就是Compose中动画的简化流程

总结

由于AnimationState是一个State,在Compose中使用会自动监听其变化,只要其value变化了,就会导致相应位置重组,然后Composable就会使用新的值来展示不同的效果,

比如最开始的示例代码:

var isOffset by remember { mutableStateOf(false) }
val offsetAnimation by animateDpAsState(targetValue = if (isOffset) 100.dp else 0.dp)
Button(
    onClick = { isOffset = !isOffset },
    modifier = Modifier.offset(0.dp, offsetAnimation)
) {
    Text(text = "点我进行位移")
}

在修改了isOffset后,animateDpAsState中的值就会因为动画的计算和修改内部state的value,导致Button的offset函数一直被重新调用,使Button不停的向下移动

其实Compose中的动画如果不考虑那么多东西的话,可以简化为如下代码:

    /**
     * creator: lt
     * effect : 自定义的动画播放器,逻辑更简单
     * warning:
     * [initialValueWithState]动画要改变的状态,起始动画值为其value值
     * [targetValue]要通过动画转化到的目标值
     * [duration]动画的持续时间
     */
    @OptIn(ExperimentalComposeApi::class)
    suspend fun animateWithFloat(
        initialValueWithState: MutableState<Float>,
        targetValue: Float,
        duration: Int = AnimationConstants.DefaultDurationMillis,
    ) {
        //动画起始值,目标差值
        val startValue = initialValueWithState.value
        val valueToBeTransformed = targetValue - startValue
        //动画起始时间,持续时间
        val startTime = System.nanoTime()
        val duration = duration * 1000000L
        //通过循环在下一帧计算动画的值
        val frameClock = coroutineContext.monotonicFrameClock
        while (System.nanoTime() <= startTime + duration) {
            frameClock.withFrameNanos {
                //计算动画的值,并设置值给状态
                val progress = minOf(it - startTime, duration).toFloat() / duration
                val increase = progress * valueToBeTransformed
                initialValueWithState.value = startValue + increase
            }
        }
    }

使用方式如下,效果跟示例差不多:

ps:不建议线上项目用这个api,还是用系统的比较好,如果想使用也可以参考(欢迎star): ComposeViews/MAnimator.kt at main · ltttttttttttt/ComposeViews (github.com)

到此这篇关于Android中分析Jetpack Compose动画内部的实现原理的文章就介绍到这了,更多相关Android Jetpack Compose内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 利用Jetpack Compose实现经典俄罗斯方块游戏

    目录 可组合函数 游戏机身 - TetrisBody 游戏按钮 - TetrisButton 游戏屏幕 - TetrisScreen 调度器 - TetrisViewModel 项目地址 你的童年是否有俄罗斯方块呢,本文就来介绍如何通过 Jetpack Compose 实现一个俄罗斯方块 ~~ 先看下效果图,功能还是挺完善的 就我自己的体验来说,使用 Compose 开发的应用我感受不到和 Android 原生开发之间有什么性能差异,但 Compose 在开发难度上会低很多 Google 官网上

  • 利用Jetpack Compose绘制可爱的天气动画

    目录 1. 项目背景 2. MyApp:CuteWeather App界面构成 3. Compose自定义绘制 声明式地创建和使用Canvas 强大的DrawScope 4.简单易用的API 使用原生Canvas 5. 雨天效果 雨滴的绘制 雨滴下落动画 6.Compose自定义布局 7.. 雪天效果 雪花的绘制 雪花飘落动画 雪花的自定义布局 8. 晴天效果 太阳的绘制 太阳的旋转 9. 动画的组合.切换 将图形组合成天气 ComposedIcon ComposedWeather 1. 项目背

  • Jetpack Compose布局的使用详细介绍

    目录 一.标准布局组件 二.修饰符 三.滑动组件 1.ScrollableRow和ScrollableColumn 2.LazyRowFor和LazyColumnFor 一.标准布局组件 Compose中可以将多个控件元素组合使用,例如下面这样, @Composable fun WidgetGroup() { Text(text = "不为往事扰") Text(text = "余生只愿笑") } 但是我们会发现,如果仅仅是这样,两个文本控件会重叠在一起,类似于下面这

  • 利用Jetpack Compose实现绘制五角星效果

    目录 说明 自定义星行Modifier 原理 实现 代码 最终实现效果 说明 compose中我们的所有ui操作,包括一些行为,例如:点击.手势等都需要使用Modifier来进行操作.因此对Modifier的理解可以帮助我们解决很多问题的 自定义星行Modifier 本文我们打算自定义一个Modifier,通过这个modifier我们可以实现用一个操作符就画出五角星的效果 原理 我们实现绘制五角星的原理如下图,首先我们会虚构两个圆,将内圆和外圆角度平分五份,然后依次连接内圆和外圆的切点的坐标,然

  • Jetpack Compose实现列表和动画效果详解

    目录 创建一个列表消息卡片 可交互的动画效果 创建一个列表消息卡片 到目前为止,我们只有一个消息的卡片,看上去有点单调,所以让我们来改善它,让它拥有多条信息.我们需要创建一个能够显示多条消息的函数.对于这种情况,我们可以使用 Compose 的 LazyColumn 和 LazyRow.这些 Composable 只渲染屏幕上可见的元素,所以它们的设计对于长列表来说很有效果.同时,它们避免了 RecyclerView 与 XML 布局的复杂性. import androidx.compose.f

  • 通过Jetpack Compose实现双击点赞动画效果

    目录 实现步骤 先红色画个爱心 点击事件加动画 完整代码 效果图 实现步骤 先红色画个爱心 Icon( Icons.Filled.Favorite, "爱心", Modifier .align(Alignment.Center) tint = Color.Red ) 点击事件加动画 双击监听 .pointerInput(Unit) { detectTapGestures( onDoubleTap = { ... } ) } #### **API 介绍** | API名称 | 作用 |

  • Jetpack Compose 实现一个图片选择框架功能

    目录 获取图片 拍照策略 NothingCaptureStrategy FileProviderCaptureStrategy MediaStoreCaptureStrategy 总结 拍照权限 取消拍照导致的脏数据 resolveActivity API 的兼容性 File API 的兼容性 Github 知乎的 Matisse应该蛮多 Android 开发者有了解过或者是曾经使用过,这是知乎在 2017 年开源的一个 Android 端图片选择框架,其颜值在现在看来也还是挺不错的 可惜近几年

  • Android中分析Jetpack Compose动画内部的实现原理

    目录 前言 正文 总结 前言 Compose的动画Api用起来很简单,效果看起来很神奇,那么它内部到底是如何运转的呢? 使用动画的代码示例: var isOffset by remember { mutableStateOf(false) } val offsetAnimation by animateDpAsState(targetValue = if (isOffset) 100.dp else 0.dp) Button( onClick = { isOffset = !isOffset }

  • Android中Property Animation属性动画编写的实例教程

    1.概述 Android提供了几种动画类型:View Animation .Drawable Animation .Property Animation .View Animation相当简单,不过只能支持简单的缩放.平移.旋转.透明度基本的动画,且有一定的局限性.比如:你希望View有一个颜色的切换动画:你希望可以使用3D旋转动画:你希望当动画停止时,View的位置就是当前的位置:这些View Animation都无法做到.这就是Property Animation产生的原因,本篇则来详细介绍

  • Jetpack Compose实现动画效果的方法详解

    目录 概述 低级别动画API animate*AsState 使用Animatable实现颜色变化效果 使用updateTransition实现颜色和圆角动画 rememberInfiniteTransition TargetBasedAnimation 自定义动画 AnimationSpec Easing AnimationVector 高级动画 概述 compose 为支持动画提供了大量的 api,通过这些 api 我们可以轻松实现动画效果 ps:这些 api 的原理与 Flutter 很接

  • Android开发Jetpack Compose元素Modifier特性详解

    目录 正文 有序性 不可变性 正文 本文将会介绍Jetpack Compose中的Modifier.在谷歌官方文档中它的描述是这么一句话:Modifier元素是一个有序.不可变的集合,它可以往Jetpack Compose UI元素中添加修饰或者各种行为.例如,背景.填充和单击事件监听器装饰或添加行为到文本或按钮.本文将会从修饰符的两个特性有序和不可变入手来探究修饰符的应用,以下是本文目录: 有序性 不可变性 有序性 官方对修饰符定义的这个特性包含两个层面的意思,一是修饰符的使用是链式的它是有先

  • Jetpack Compose惯性衰减动画AnimateDecay详解

    目录 什么是惯性衰减动画 惯性衰减动画 使用要点 block 监听 什么是惯性衰减动画 比如说我们玩微信的时候 手指一拉,微信的列表就会惯性滑动 ,这个滑动的速率当然是越来越慢的,最终停止, 这个其实就是惯性衰减动画的典型例子 那这个例子和animateTo 有啥区别呢? 一个速率变慢的动画 ,听起来似乎 我们用animateTo 设置一些参数也可以实现 其实这里最大的区别就是 animateTo 你是需要设置目标值的,也就是动画结束的那一刻 某个view属性的值 你必须明确指定 而所谓的惯性衰

  • Jetpack Compose自定义动画与Animatable详解

    目录 AnimationSpec 1.spring 2.tween 3.keyframes 4.repeatable 5.snap Animatable 本篇主要是自定义动画与Animatable. AnimationSpec 上一篇中,出现了多次animationSpec属性,它是用来自定义动画规范的.例如: fun Modifier.animateContentSize( animationSpec: FiniteAnimationSpec<IntSize> = spring(), fin

  • Android中关于JSON相关应用分析

    本文分析了Android中关于JSON相关应用.分享给大家供大家参考,具体如下: JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式,获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换.JSON采用兼容性很高的文本格式,同时也具备类似于C语言体系的行为. – Json.org JSON的结构: Name/Value Pairs,类似所熟知的Keyed list. Hash table.Discti

  • 详解Android中Handler的内部实现原理

    本文主要是对Handler和消息循环的实现原理进行源码分析,如果不熟悉Handler可以参见博文<详解Android中Handler的使用方法>,里面对Android为何以引入Handler机制以及如何使用Handler做了讲解. 概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功

随机推荐