Compose 动画入门 (二) : 为什么animateDpAsState要用val ? MutableState和State有什么区别 ?

news2024/11/17 14:19:27

1. 前言

我们首先来实现一个Compose的动画(animateDpAsState)

var big by remember {
    mutableStateOf(false)
}
val size by animateDpAsState(if (big) 100.dp else 50.dp)

Box(
    Modifier
        .size(size)
        .background(Color.Blue)
        .clickable {
            big = !big
        }) {

}

运行程序,来看下效果
在这里插入图片描述
仔细看代码,我们可以发现,有这些疑问

  • 为什么animateDpAsState要用val ? 而mutableStateOf就用var ?
  • MutableStateState有什么区别 ?
  • 为什么animateDpAsState不需要包remember ?
  • 为什么把mutableStateOf替换为animateDpAsState,就可以实现动画渐变的效果 ?

接下来,我们带着疑问就来看一些这几个疑问。

2. 为什么animateDpAsState要用val ?

我们分别点进animateDpAsStatemutableStateOf,发现他们的返回值有区别

animateDpAsState :

@Composable
fun animateDpAsState(
    targetValue: Dp,
    animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
    finishedListener: ((Dp) -> Unit)? = null
): State<Dp> {
    return animateValueAsState(
        targetValue,
        Dp.VectorConverter,
        animationSpec,
        finishedListener = finishedListener
    )
}

mutableStateOf:

fun <T> mutableStateOf(
    value: T,
    policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T> = createSnapshotMutableState(value, policy)

animateDpAsState返回值是State,而mutableStateOf的返回值是MutableState
正是StateMutableState的区别,导致animateDpAsState需要使用val,而mutableStateOf使用var

3. MutableState和State有什么区别 ?

StateMutableState有什么区别呢 ?
我们查看源码可知

@Stable
interface MutableState<T> : State<T> {
    override var value: T
    operator fun component1(): T
    operator fun component2(): (T) -> Unit
}

@Stable
interface State<out T> {
    val value: T
}

MutableState继承自State,都有value这个值。value这个值改变的时候,Compose会进行hook,从而通知界面改变的。

MutableStateState的区别在于, State是只读的,而MutableState是可写可读的

从代码中我们也可以看出

State实现了kotlin委托机制中的getValue

inline operator fun <T> State<T>.getValue(thisObj: Any?, property: KProperty<*>): T = value

MutableState才实现了kotlin委托机制中的setValue

inline operator fun <T> MutableState<T>.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
    this.value = value
}

如果有童鞋不知道Kotlin委托的,可以看我的另一篇博客 看似普通的Android开发黑科技 - Kotlin 委托

所以animateValueAsState为什么要返回State呢 ? 相比答案也很明确了,因为动画是需要时间去过渡的,所以value的变化需要交给内部去处理,不能直接给value进行赋值,只能去指定目标值targetValue

4. 为什么animateDpAsState不需要包remember ?

我们点击animateValueAsState,查看其内部源码,可以发现其内部已经包了remember,所以就不需要我们自己再调用remember了,但这也意味着animateXXXAsState只能在Composable函数内部调用了,可以看到代码中都有@Composable注解。

@Composable
fun <T, V : AnimationVector> animateValueAsState(
    targetValue: T,
    typeConverter: TwoWayConverter<T, V>,
    animationSpec: AnimationSpec<T> = remember {
        spring(visibilityThreshold = visibilityThreshold)
    },
    visibilityThreshold: T? = null,
    finishedListener: ((T) -> Unit)? = null
): State<T>

5. 为什么把mutableStateOf替换为animateDpAsState,就可以实现动画渐变的效果 ?

到这里,我们想必已经明白了,animateDpAsState的返回值是State,其内部的value只能通过内部改变,从而更新Compose界面,animateDpAsState内部已经帮我们处理好动画渐变值平滑的过度了。

@Composable
fun <T, V : AnimationVector> animateValueAsState(
    targetValue: T,
    typeConverter: TwoWayConverter<T, V>,
    animationSpec: AnimationSpec<T> = remember {
        spring(visibilityThreshold = visibilityThreshold)
    },
    visibilityThreshold: T? = null,
    finishedListener: ((T) -> Unit)? = null
): State<T> {
    val animatable = remember { Animatable(targetValue, typeConverter) }
    val listener by rememberUpdatedState(finishedListener)
    val animSpec by rememberUpdatedState(animationSpec)
    val channel = remember { Channel<T>(Channel.CONFLATED) }
    SideEffect {
        channel.trySend(targetValue)
    }
    LaunchedEffect(channel) { //Compose中的协程
        for (target in channel) {
            // This additional poll is needed because when the channel suspends on receive and
            // two values are produced before consumers' dispatcher resumes, only the first value
            // will be received.
            // It may not be an issue elsewhere, but in animation we want to avoid being one
            // frame late.
            val newTarget = channel.tryReceive().getOrNull() ?: target
            launch {
                if (newTarget != animatable.targetValue) {
                    animatable.animateTo(newTarget, animSpec) //平滑过度到目标值
                    listener?.invoke(animatable.value)
                }
            }
        }
    }
    return animatable.asState()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/149745.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第56篇-利用JSRpc分析某尾波的登录参数【2023-01-09】

声明:该专栏涉及的所有案例均为学习使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!如有侵权,请私信联系本人删帖! 文章目录 一、前言二、JsRpc的基本使用1.准备工作2.简单使用三、利用JSRpc分析尾波的登录参数1.网站分析2.构建rpc一、前言 以前使…

LabVIEW控制前面板对象

LabVIEW控制前面板对象控件引用句柄在引用句柄和经典引用句柄选板上&#xff0c;它可将前面板对象的引用传输给其它VI。右键单击前面板对象&#xff0c;从快捷菜单中选择创建引用&#xff0c;可建立一个VI服务器引用。而且&#xff0c;也可在程序框图上的VI服务器常量中找到前面…

2023年01月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年01月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…

高性能分布式缓存Redis-第一篇章

高性能分布式缓存Redis-第一篇章一、缓存发展史&缓存分类1.1、大型网站中缓存的使用1.2、常见缓存的分类1.3、分布式缓存选型方案对比二、Redis概述&安装配置2.1、概述2.2、安装&配置三、数据类型选择&应用场景3.1、Redis的Key的设计规范3.1.1、key名设计3.1.2…

Linux中常用命令(初学整理附实例和自己的理解)

目录 00.tree命令 01. ls 指令 02. pwd命令 03. cd 指令 04. touch指令 05.mkdir指令 06.rmdir指令 && rm 指令 07.man指令 08.热键tab键 09.nano 10.stat 11.cp指令 12.mv指令 13. cat 14.more指令 15.less指令 16.head指令 17.tail指令 18.wc 19.echo 20.…

运营商云从ATH虎口夺食?

配图来自Canva可画 如今在云计算领域&#xff0c;国内市场与国际市场的分化越来越显著&#xff0c;国内市场也在走出与国际市场不同的路径&#xff0c;而其中最大的变量则是来自三大运营商的进场与冲击。 以天翼云、联通云以及移动云为代表&#xff0c;国内通讯运营商的云品牌…

挑战杯课外学术参赛作品—AI合约问卷调查系统

大学生课外学术科技作品竞赛 1.作品概述 1.1作品选题背景和意义 随着互联网技术的发展以及大数据、人工智能等新科技时代的来临&#xff0c;我国高校教育改革、高校人才培养也面临着新的机遇与挑战。一方面&#xff0c;为了实现国家战略、支撑快速发展的新经济&#xff0c;需…

这是一个基于Threejs的商品VR展示系统的 VR模型展示Demo

vr-cake-demo 这是一个基于Threejs的商品VR展示系统的 VR模型展示Demo Demo界面示意图 Demo蛋糕实物图片 Demo蛋糕VR效果图 研究意义 2020年&#xff0c;已经进入了5G时代&#xff0c;许许多多的行业都得开启了高速发展模式&#xff0c;自动驾驶行业&#xff0c;人工智能行业…

硬核实力!企企通荣获“千峰奖·2022年度产业互联网百强”

12月28日&#xff0c;由亿邦动力主办的首届“亿邦跨境产业互联网峰会暨2022年度千峰奖颁奖盛典”在武汉举办&#xff0c;大会现场揭晓了本年度千峰奖获奖企业名单。企企通作为采购供应链领导者&#xff0c;凭借在采购数字化领域的创新引领和硬核实力&#xff0c;荣获“千峰奖20…

Webpack实现多页面打包

1. 多页面应用(MPA)概念 单页面在开发时会把所有的业务放在一个大的入口里面去&#xff0c;不同的子业务还是同一个URL地址&#xff0c;只不过后面的hash会有所不同。 多页面相对于单页面的区别在于&#xff0c;项目发布上线以后&#xff0c;有多个入口文件&#xff0c;每一次…

排障定位时间缩短一半以上, 博睿数据如何赋能青岛住房公积金管理中心

*本文源自快科技&#xff0c;原文链接&#xff1a; https://news.mydrivers.com/1/882/882428.htm 近日&#xff0c;青岛公积金发布关于住房公积金的两则新政&#xff0c;惠及历史高商贷利率人群与多子女家庭。同时&#xff0c;为了让更广泛的人民群众享有到更加优质的公积金…

类加载器子系统

一、内存结构概述 通过类加载子系统将Class字节码文件加载到内存中 更细致的结构图&#xff1a; 二、类加载器与类的加载过程 2.1、类加载过程 通过一个类的全限定名获取定义此类的二进制字节流将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构在内存中生成一个…

大米CMS_V5.5.3 SQL注入漏洞分析

0x00 环境准备 大米CMS官网&#xff1a;http://www.damicms.com 网站源码版本&#xff1a;大米CMS_V5.5.3试用版(更新时间&#xff1a;2017-04-15) 程序源码下载&#xff1a;http://www.damicms.com/downes/dami.rar 测试网站首页&#xff1a; 0x01 代码分析 1、首先来看…

【Qt】QtCreator新建QtWidgetsApplication

【Qt】QtCreator新建QtWidgetsApplication1、背景2、新建项目3、项目文件4、编译说明1、背景 操作系统&#xff1a;windows10专业版。 Qt版本&#xff1a;qt-opensource-windows-x86-msvc2013_64-5.7.1.exe 注意&#xff1a;安装了该exe可执行文件&#xff0c;就自动安装了qtc…

【openGauss实战3】基本概念及语法

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…

创建Vuex时没有$store的解决

为什么会出现这个问题呢&#xff1f;就是因为你的vuex安装的版本是最新版本 vue3版本对应的是 vue2 vue4版本对应的是 vue3 如果你在vue2项目中&#xff0c;所有的配置好了&#xff0c;组件中就是没有$store属性&#xff0c;那么很有可能是安装的vuex插件版本过高 store…

ArcGIS Pro脚本工具(16)——要素类转txt坐标文件

之前介绍过txt坐标文件如何转为GIS要素类 ArcGIS Pro脚本工具&#xff08;8&#xff09;——txt坐标文件转shp_学学GIS的博客-CSDN博客_txt转shp国土部门给过来的数据经常需要转换&#xff0c;比如土地报批和高标准农田的数据经常给一个txt文件过来&#xff0c;不能直接在GIS软…

Python状态机(transitions模块)

文章目录1、为什么要用状态机&#xff1f;2、状态机是什么&#xff1f;3、状态图是什么&#xff1f;4、transitions是什么&#xff1f;官网安装使用状态机必须定义的两个要素二、实战应用1、规划state、transitionstate&#xff1a;状态节点的说明transition&#xff1a;状态转…

昆腾微冲刺创业板上市:计划募资5亿元,股权结构较为分散

撰稿|汤汤 来源|贝多财经 近日&#xff0c;北京昆腾微电子股份有限公司&#xff08;下称“昆腾微”&#xff09;在深圳证券交易所递交招股书&#xff0c;准备在创业板上市。本次冲刺上市&#xff0c;昆腾微计划募资5.07亿元&#xff0c;拟用于音频SoC芯片升级、产业化项目&am…

(5)go-micro微服务domain层开发

文章目录一 domain层介绍说明二 model层开发三 repository层开发四 service层开发五 最后一 domain层介绍说明 domain层专注于数据库数据领域开发&#xff0c;我们把数据库相关操作全部写在domain层。 model层&#xff1a;数据表字段定义与开发 repository层&#xff1a;数据…