当前位置: 首页 > news >正文

Compose 实践与探索五 —— AnimationSpec

不论是 animateXxxAsState() 还是 Animatable 的 animateTo() 都可以传入 AnimationSpec 以配置动画的规格:

@Composable
fun animateDpAsState(targetValue: Dp,animationSpec: AnimationSpec<Dp> = dpDefaultSpring,label: String = "DpAnimation",finishedListener: ((Dp) -> Unit)? = null
)suspend fun animateTo(targetValue: T,animationSpec: AnimationSpec<T> = defaultSpringSpec,initialVelocity: T = velocity,block: (Animatable<T, V>.() -> Unit)? = null
): AnimationResult<T, V>

比如对于上节方块变大变小的例子,可以指定一个弹簧效果:

anim.animateTo(size, spring(Spring.DampingRatioMediumBouncy))

spring() 会返回 SpringSpec,是 animateTo() 要求的 AnimationSpec 的实现类。为了全面了解 AnimationSpec,我们先查看一下 AnimationSpec 的继承树。

Android Studio 使用技巧:将光标放在想要查看的类上,通过 Ctrl + H 查看该类的继承关系。

Compose 中有多个 AnimationSpec 的接口,除了 AnimationSpec,还有 VectorizedAnimationSpec、DecayAnimationSpec、FloatDecayAnimationSpec、VectorizedDecayAnimationSpec 等接口都有各自的继承树。这一节我们主要介绍 AnimationSpec 继承树中的内容:

在这里插入图片描述

1、TweenSpec

看到 Tween 这个单词容易联想到试图动画 View Animation 中的补间动画 Tween Animation,但是这两个 Tween 从程序角度上看没有任何关联,不要试图以补间动画的知识去理解 TweenSpec。

Tween 是一个有些古老的词汇,它来自于动画领域的 Inbetween,是指动画主创在完成关键帧后,由助手完成关键帧之间的补帧工作。后续发展成 Tween 这个词,在程序领域中,指程序员指定起始帧和结束帧,然后由程序完成两帧之间的动画补全。

TweenSpec 的主构造有三个参数:

@Immutable
class TweenSpec<T>(// 动画时长,默认值是 300msval durationMillis: Int = DefaultDurationMillis,// 动画启动延时val delay: Int = 0,// 缓动,动画曲线设置val easing: Easing = FastOutSlowInEasing
) : DurationBasedAnimationSpec<T>

easing 这个单词不论是 Google 的官方翻译还是业界的通用翻译都是“缓动”,指动画是如何进行渐变的,也就是动画曲线。通常我们会从 Compose 提供的四个 Easing 中选取一个使用:

/**
* 从静止状态开始并结束于静止状态的元素使用这种标准的缓动效果。它们会快速加速并逐渐减速,
* 以强调过渡的结束部分。
* 标准缓动通过在减速阶段分配比加速阶段更多的时间,将细微的注意力集中在动画的结尾部分。
* 这是最常见的缓动形式。
* 这相当于 Android 中的 FastOutSlowInInterpolator。
*/
val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)/*** 进入的元素使用减速缓动进行动画处理,这种缓动效果使过渡以峰值速度(元素运动的最快点)开始,* 并以静止状态结束。* 这相当于 Android 中的 LinearOutSlowInInterpolator。*/
val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)/*** 退出屏幕的元素使用加速缓动效果,它们从静止状态开始,并以峰值速度结束。** 这相当于 Android 中的 FastOutLinearInInterpolator。*/
val FastOutLinearInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f)/*** 它直接返回未经修改的分数值。这在需要一个 [Easing] 但实际上不需要任何缓动效果的情况下,* 作为默认值非常有用。*/
val LinearEasing: Easing = Easing { fraction -> fraction }

四种 Easing 的简介:

  • FastOutSlowInEasing 相当于属性动画中的 AccelerateDecelerateInterpolator,它加速入场并减速出场,也就是说入场和出场时都是慢速的,在中间过程是快速的
  • LinearOutSlowInEasing 是入场速度较快,匀速减速到 0 的曲线,适合做元素入场动画,相当于属性动画的 DecelerateInterpolator
  • FastOutLinearInEasing 从静止开始加速退出屏幕,相当于 AccelerateInterpolator
  • LinearEasing 的动画曲线是一条直线,也就是匀速的

使用时,可以通过 TweenSpec 的构造函数:

anim.animateTo(size, TweenSpec(easing = FastOutSlowInEasing))

也可以使用 Compose 提供的简便函数:

anim.animateTo(size, tween())

简便函数大概只是为了让我们少写几个字母吧,它的参数以及默认值与 TweenSpec 构造函数完全一样:

@Stable
fun <T> tween(durationMillis: Int = DefaultDurationMillis,delayMillis: Int = 0,easing: Easing = FastOutSlowInEasing
): TweenSpec<T> = TweenSpec(durationMillis, delayMillis, easing)

大多数情况下使用现有的四个 Easing 即可,但开发过程难免有需要自己定制的时候,参照现成的实现,都是使用了三阶贝塞尔曲线 CubicBezierEasing():

@Immutable
class CubicBezierEasing(private val a: Float,private val b: Float,private val c: Float,private val d: Float
) : Easing

三阶贝塞尔曲线取消四个点才能确定,其中起点固定为 (0,0),终点固定为 (1,1),剩下两个点的四个坐标就是 CubicBezierEasing() 的四个参数。至于如何确定这四个参数,可以借助一个三阶贝赛尔曲线的动画网站来确定:

在这里插入图片描述

左侧坐标的横轴表示时间,纵轴表示动画进度,如上图所示就是 CubicBezierEasing 的图像。

2、SnapSpec

SnapSpec 与 TweenSpec 是兄弟,它的效果与前面介绍过的 Animatable 的 snapTo() 是一样的效果。当 animateTo() 使用 SnapSpec 时,与直接使用 snapTo() 的唯一区别是 SnapSpec 可以增加一个延时:

anim.animateTo(size, SnapSpec(3000))

SnapSpec 也有个简便函数 snap():

anim.animateTo(size, snap(3000))

3、KeyframesSpec

Keyframes 是关键帧的意思,意味着在动画运行过程中可以选取几个关键的时间点,给出对应时间点的动画完成度,KeyframesSpec 就可以根据这些信息计算出整个动画完整的速度曲线。可以看作分段式的 TweenSpec,即将整个动画按照时间点分段,每一段都是一个 TweenSpec。

KeyframesSpec 的构造函数只有一个参数 KeyframesSpecConfig,可以配置动画属性:

@Immutable
class KeyframesSpec<T>(val config: KeyframesSpecConfig<T>) : DurationBasedAnimationSpec<T> {class KeyframesSpecConfig<T> {// 动画时长var durationMillis: Int = DefaultDurationMillis// 动画延时启动var delayMillis: Int = 0// 关键帧internal val keyframes = mutableMapOf<Int, KeyframeEntity<T>>()// 中缀函数用于指定时间点infix fun T.at(/*@IntRange(from = 0)*/ timeStamp: Int): KeyframeEntity<T> {return KeyframeEntity(this).also {keyframes[timeStamp] = it}}...}
}

基于以上源码,如果想通过 KeyframesSpec 的构造函数创建动画,大致代码如下:

// 创建 KeyframesSpecConfig 对象通过 apply() 指定具体属性
anim.animateTo(size, KeyframesSpec(KeyframesSpec.KeyframesSpecConfig<Dp>().apply {durationMillis = 450delayMillis = 500144.dp at 150 with FastOutLinearInEasing20.dp at 300
}))

这样写起来很麻烦,因此 Compose 提供了简便方法 keyframes():

// size 是动画的目标值,也就是终点值
anim.animateTo(size, keyframes {// 指定动画时长为 450msdurationMillis = 450delayMillis = 500// 指定在 150ms 时 size 为 144dp,并且从 150ms 这个时间点// 开始的这一段动画曲线为 FastOutLinearInEasing144.dp at 150 with FastOutLinearInEasing// 指定在 300ms 时 size 为 20dp,没有显式指定 Easing,默认// 使用 LinearEasing20.dp at 300
})

看到这里应该能理解为什么 TweenSpec 和 SnapSpec 有简便方法了,其实主要还是为了给 KeyframesSpec 提供简便方法 keyframes(),同时为了保持一致,就把另外两个也带上了。

使用 KeyframesSpec 有一个限制,就是这样写动画复用性降低了。比如要实现一个反向动画,只能 需要重新写一个 keyframes()。

到这里,DurationBasedAnimationSpec 的三个子类就介绍完了,DurationBased 意思是动画时长都是确定的。

4、SpringSpec

与 DurationBasedAnimationSpec 是兄弟关系的 Spec 有两个 —— SpringSpec 和 RepeatableSpec,本节我们先介绍 SpringSpec。

既然 SpringSpec 是 DurationBasedAnimationSpec 的兄弟,那意味着 SpringSpec 不具备 DurationBasedAnimationSpec 可以确定动画时长的特性。动画有不基于时长的吗?似乎原生的属性动画都是有动画时长的,Compose 却没有?实际上,这种认识是错误的。原生的属性动画确实都有动画时长,但是却没有 SpringSpec 这种基于物理模型的弹簧动画。因此 Compose 不仅没有落后于属性动画,反而是相对于原生增加了一种大的动画类别。

此外,Jetpack 库也提供过弹簧动画的扩展库,同样也是不能设置动画时长的,因为基于物理模型的动画没办法设定一个准确的动画时长。

具体使用上,我们来看前面已经提到过的 spring 函数:

/**
* 创建一个使用给定弹簧常量(即阻尼比和刚度)的 SpringSpec。可选的 visibilityThreshold 
* 定义了当动画在视觉上足够接近目标值时,可以将其舍入到目标值。
* 参数:
* dampingRatio - 弹簧的阻尼比。默认为 Spring.DampingRatioNoBouncy。
* stiffness - 弹簧的刚度。默认为 Spring.StiffnessMedium。
* visibilityThreshold - 可选参数,指定可见性阈值。
*/
@Stable
fun <T> spring(dampingRatio: Float = Spring.DampingRatioNoBouncy,stiffness: Float = Spring.StiffnessMedium,visibilityThreshold: T? = null
): SpringSpec<T> =SpringSpec(dampingRatio, stiffness, visibilityThreshold)

dampingRatio 是弹簧的阻尼比,它决定了弹簧有多“弹”。合法值是一个大于 0 的 Float,值越小,弹簧越弹。默认值为 1,此时弹簧不会来回弹,而是到达目标值之后就不弹了。当值大于 1 时,值越大,弹簧的弹性越差,到达目标值的时间就越长。

stiffness 是弹簧的刚度,指弹簧在受到外力作用时,产生单位变形所需的载荷。刚度越大,压缩之后越容易回弹。假如向做一个阻尼小,刚度也小的动画:

// 阻尼 0.2f,刚度 50f
anim.animateTo(size, spring(Spring.DampingRatioHighBouncy, Spring.StiffnessVeryLow))

那么展现出的效果就是弹簧来回弹的次数很多(阻尼低),但是弹的速度很慢(刚度低)。

最后一个参数 visibilityThreshold,可见性阈值,指弹簧偏离原点多远时强制让弹簧的运动停下来。设置它主要是为了防止阈值过小导致肉眼不可见或阈值过大导致用户还能看到界面时就突然停止了。

animateTo() 使用 SpringSpec 时可以搭配初速度实现震动效果:

anim.animateTo(size,spring(Spring.DampingRatioHighBouncy, Spring.StiffnessVeryLow),2000.dp // 初始速度
)

5、RepeatableSpec

RepeatableSpec 用于重复播放动画,我们直接看它的简便方法 repeatable():

/**
* 创建一个 RepeatableSpec,用于播放基于时间的 DurationBasedAnimationSpec(例如 TweenSpec、
* KeyframesSpec),并按照 iterations 指定的次数重复播放。
* 迭代次数描述了动画将运行的次数。1 表示不重复。如果需要创建无限重复的动画,建议使用 infiniteRepeatable。
*
* 注意:在 RepeatMode.Reverse 模式下重复时,强烈建议使用奇数的迭代次数。否则,动画
* 在完成最后一次迭代时可能会跳转到结束值。
* 
* initialStartOffset 可用于延迟动画的开始或将动画快进到给定的播放时间。此起始偏移量不会重复,
* 而动画中的延迟(如果有)将会重复。默认情况下,偏移量为 0。
*/
@Stable
fun <T> repeatable(// 总迭代次数,应大于 1 以实现重复iterations: Int,// 需要重复的动画animation: DurationBasedAnimationSpec<T>,// 动画重复的方式,是从头开始(即 RepeatMode.Restart)还是从末尾开始(即 RepeatMode.Reverse)repeatMode: RepeatMode = RepeatMode.Restart,// 动画的起始偏移量initialStartOffset: StartOffset = StartOffset(0)
): RepeatableSpec<T> =RepeatableSpec(iterations, animation, repeatMode, initialStartOffset)

参数讲解:

  1. iterations:总迭代次数,就是动画播放的次数,大于 1 才能重复播放动画,填 1 不重复,填 0 报错
  2. animation:需要重复的动画,类型必须是 DurationBasedAnimationSpec,也就是其子类的 TweenSpec、SnapSpec 以及 KeyframesSpec 之一
  3. repeatMode:动画重复的方式,有两种选择,从头开始(即 RepeatMode.Restart)还是从末尾开始(即 RepeatMode.Reverse),需要注意如果是 RepeatMode.Reverse 的话,iterations 必须是一个奇数,否则,动画在完成最后一次迭代时可能会跳转到结束值
  4. initialStartOffset:动画起始偏移量,这个是时间上的偏移量,而不是位置上的偏移量

解释一下为什么 repeatMode 是 RepeatMode.Reverse 时 iterations 必须是奇数。比如动画的初始值是 48,目标值是 96,Reverse 模式下 iterations 为 2。那么 48 -> 96 是第一次,第二次倒放就是 96 -> 48,由于我们是通过 animateTo() 指定目标值并展示动画,因此动画结束时必须在目标值 96 上,因此这里会有一个 48 直接跳到 96 的变化,这与设定的倒放 2 次最终应该处于 48 的结果不符。

一种解决方案是使用 KeyframesSpec 设置起始值和目标值都为 48,中间放一个关键帧,值为 96,这样就做出了上面那种 48 -> 96 -> 48 的重复效果了。

最后再详细说一下 initialStartOffset,其类型是 StartOffset,主构造被设置成 private 的,次构造提供了两个参数:

@kotlin.jvm.JvmInline
value class StartOffset private constructor(internal val value: Long) {/*** 为 [repeatable] 和 [infiniteRepeatable] 创建一个起始偏移量。[offsetType] 可以是以下两种之一:* [StartOffsetType.Delay] 和 [StartOffsetType.FastForward]。[offsetType] 默认为 * [StartOffsetType.Delay]** [StartOffsetType.Delay] 会将动画的开始延迟 [offsetMillis] 指定的时间,而* [StartOffsetType.FastForward] 会立即从动画的 [offsetMillis] 处开始播放动画。*/constructor(offsetMillis: Int, offsetType: StartOffsetType = StartOffsetType.Delay) : this((offsetMillis * offsetType.value).toLong())
}

第一个参数就是以毫秒为单位的偏移量,第二个参数 offsetType 有两种类型可选:

  • Delay:延时模式,即为动画设置启动延时,在 offsetMillis 这么长时间后再开始播放动画
  • FastForward:立即播放模式,跳过前 offsetMillis 毫秒的动画,快进到 offsetMillis 这个时间点开始播放后续动画

6、InfiniteRepeatableSpec

前面讲到的 DurationBasedAnimationSpec、RepeatableSpec 以及 SpringSpec 是 FiniteAnimationSpec 接口的子类或子接口,而接下来要介绍的 InfiniteRepeatableSpec 与 FiniteAnimationSpec 是兄弟关系。

InfiniteRepeatableSpec 用于展示无限循环的动画,它与 RepeatableSpec 在本质上是没有区别的,只不过循环次数一个是有限的,一个是无限的,并且有限循环的 RepeatableSpec 可以计算出总的动画时长。

如果一个动画使用了 InfiniteRepeatableSpec,那动画何时会结束,这个过程中会涉及到内存泄漏或者性能损耗吗?

animateTo() 结束的时候,动画就结束了。因为 animateTo() 是挂起函数,它需要在 LaunchedEffect() 营造的协程环境中才能调用,当 LaunchedEffect() 结束时,就会让 animateTo() 结束。而 LaunchedEffect(key) 会在 key 发生变化时重新启动,当它重启时,上一次执行的 LaunchedEffect() 就会自动结束。

当 animateTo() 所在的协程结束时动画就会停止,不会有性能损耗或内存泄漏。

7、其他 Spec

AnimationSpec 接口一共有三个子类或子接口:FiniteAnimationSpec 和 InfiniteRepeatableSpec 我们已经讲过,还剩下一个 FloatAnimationSpec 接口:

@JvmDefaultWithCompatibility
interface FloatAnimationSpec : AnimationSpec<Float> {...}

这个接口把 AnimationSpec 的泛型类型直接实例化为 Float,因此它的两个子类 FloatTweenSpec 与 FloatSpringSpec 就是针对 Float 类型的动画规格了。

既然已经有了支持通用类型的 TweenSpec 和 SpringSpec,为什么还要单独为 Float 类型做对应的类呢?实际上 FloatTweenSpec 与 FloatSpringSpec 是为 Compose 更底层的动画计算做辅助工作的,不是给上层开发用的。因此,不要去使用这两个类。

在 AnimationSpec 之外,还有其他的 AnimationSpec 接口:

  • VectorizedAnimationSpec:也是辅助底层动画计算的接口,它的继承树结构与 AnimationSpec 的十分相似。Vectorized 译为向量化,因为 Compose 底层计算动画都是要先统一转成向量,也就是密封类 AnimationVector 中的 AnimationVector1D ~ AnimationVector4D
  • DecayAnimationSpec:消散型动画,马上会与 Animatable 的 animateDecay() 一起讲解

相关文章:

Compose 实践与探索五 —— AnimationSpec

不论是 animateXxxAsState() 还是 Animatable 的 animateTo() 都可以传入 AnimationSpec 以配置动画的规格&#xff1a; Composable fun animateDpAsState(targetValue: Dp,animationSpec: AnimationSpec<Dp> dpDefaultSpring,label: String "DpAnimation",…...

Embedding模型到底是什么?

嵌入模型&#xff08;Embedding Model&#xff09;是一种将高维数据映射到低维空间的工具&#xff0c;广泛应用于自然语言处理&#xff08;NLP&#xff09;、推荐系统和图像识别等领域。它的核心目标是将复杂的数据&#xff08;如文本、图像或用户行为&#xff09;转换为稠密的…...

数据结构(一)——绪论

一、数据结构的研究内容 1.数据的各种逻辑结构和物理结构&#xff0c;以及他们之间的相应关系 2.存储结构的方法&#xff0c;对每种结构定义相适应的各种运算 3.设计出相应的算法 4.分析算法的效率 二、数据结构的基本概念 1.数据&#xff08;data&#xff09;&#xff1a…...

VMware虚拟机网络连接模式介绍以及nat模式访问公网实践

在 VMware 虚拟机中&#xff0c;网络配置是非常重要的一部分。VMware 提供了三种主要的网络连接模式&#xff0c;分别是桥接模式&#xff08;Bridged&#xff09;、NAT模式&#xff08;NAT&#xff09; 和仅主机模式&#xff08;Host-Only&#xff09;。每种模式都有其特定的用…...

Selenium Manager和webdriver manager的区别与联系

一、引言 1.1 自动化测试的重要性 在现代软件开发流程中&#xff0c;自动化测试已经成为保证软件质量和提高交付效率的关键实践。随着软件开发周期的缩短和软件复杂性的增加&#xff0c;手工测试已无法满足快速迭代的需求。自动化测试能够快速、准确地执行重复性测试任务&…...

八叉树地图的原理与实现

八叉树与体素图 八叉树地图 八叉树地图是可变分辨率的三维栅格地图&#xff0c;可以自由调整分辨率&#xff0c;如下所示&#xff1a; 根据点云的数量或密度决定每个叶子方块是否被占据 体素图 体素就是固定分辨率的三维栅格地图&#xff0c;如下所示&#xff1a; 根据点云…...

DeepSeek模型本地化部署方案及Python实现

DeepSeek实在是太火了&#xff0c;虽然经过扩容和调整&#xff0c;但反应依旧不稳定&#xff0c;甚至小圆圈转半天最后却提示“服务器繁忙&#xff0c;请稍后再试。” 故此&#xff0c;本文通过讲解在本地部署 DeepSeek并配合python代码实现&#xff0c;让你零成本搭建自己的AI…...

【Linux】浅谈冯诺依曼和进程

一、冯诺依曼体系结构 冯诺依曼由 输入设备、输出设备、运算器、控制器、存储器 五部分组成。 冯诺依曼的设计特点 二进制表示 所有数据&#xff08;包括程序指令&#xff09;均以二进制形式存储和运算&#xff0c;简化了硬件逻辑设计&#xff0c;提高了可靠性。 存储程序原理…...

基于深度学习的多模态人脸情绪识别研究与实现(视频+图像+语音)

这是一个结合图像和音频的情绪识别系统&#xff0c;从架构、数据准备、模型实现、训练等。包括数据收集、预处理、模型训练、融合方法、部署优化等全流程。确定完整系统的组成部分&#xff1a;数据收集与处理、模型设计与训练、多模态融合、系统集成、部署优化、用户界面等。详…...

【蓝桥杯】第15届c++B组--R格式

问题描述 小蓝最近在研究一种浮点数的表示方法&#xff1a;RR 格式。对于一个大于 0 的浮点数 dd&#xff0c;可以用 RR 格式的整数来表示。给定一个转换参数 nn&#xff0c;将浮点数转换为 RR 格式整数的做法是: 将浮点数乘以 2n2n&#xff1b; 四舍五入到最接近的整数。 …...

【初阶三】认识C语言—下

【初阶三】认识C语言—下 1.函数2.数组3.操作符3.1算数操作符3.2移位操作符和位操作符3.3赋值操作符3.4单目操作符 4.常见关键字4.1关键字typedef4.2 关键字static 5. define定义常宏6.指针6.1内存6.2取地址操作符& 7.结构体 1.函数 函数就像一个工厂&#xff0c;通过输入原…...

【C#】使用DeepSeek帮助评估数据库性能问题,C# 使用定时任务,每隔一分钟移除一次表,再重新创建表,和往新创建的表追加5万多条记录

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…...

前端学习笔记(三)——ant-design vue表单传递数据到父页面

前言 善用AI&#xff0c;快速解决定位 原理 a-form所在的SFC&#xff08;单文件&#xff09;vue中需要将表单数据传递给父页面SFC文件中&#xff0c;使用emit方法 代码 子组件&#xff08;Form.vue&#xff09; <template><a-form submit"handleSubmit&qu…...

计算机视觉算法实战——驾驶员玩手机检测(主页有源码)

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​​​ 1. 领域简介&#xff1a;玩手机检测的重要性与技术挑战 驾驶员玩手机检测是智能交通安全领域的核心课题。根据NHTSA数据&#xff0…...

C语言(23)

字符串函数 11.strstr函数 1.1函数介绍&#xff1a; 头文件&#xff1a;string.h char *strstr ( const char * str1,const char *str2); 作用&#xff1a;在一个字符串&#xff08;str1&#xff09;中寻找另外一个字符串&#xff08;str2&#xff09;是否出现过 如果找到…...

Python入门教程:从零开始学习Python编程

引言 Python是一种高级编程语言&#xff0c;因其简洁的语法和强大的功能而广受欢迎。无论你是编程新手&#xff0c;还是有经验的开发者&#xff0c;Python都是一个非常好的选择。本文将带你从零开始学习Python编程&#xff0c;涵盖基础语法、常用库以及一些实用的编程技巧。 目…...

SAIL-RK3576核心板应用方案——无人机视觉定位与地面无人设备通信控制方案

本方案以 EFISH-RK3576-SBC工控板 或 SAIL-RK3576核心板 为核心&#xff0c;结合高精度视觉定位、实时通信与智能控制技术&#xff0c;实现无人机与地面无人设备的协同作业。方案适用于物流巡检、农业植保、应急救援等场景&#xff0c;具备高精度定位、低延迟通信与强环境适应性…...

14.C语言const的使用规范,详细说明

目录 修饰变量 修饰指针 指向常量的指针 常量指针 指向常量的常量指针 修饰函数参数 修饰函数返回值 总结 在 C 语言里&#xff0c;const 是一个类型限定符&#xff0c;它的作用是将变量定义为只读&#xff0c;也就是不允许对其值进行修改&#xff0c;用来修饰函数中的…...

安装操作系统ubuntu-20.04.6-live-server-amd64

一、下载虚拟机软件、远程控制软件及操作系统镜像 下载VMware Workstation&#xff1a; 下载 VMware Workstation Pro 个人免费版(可能会访问不了&#xff0c;那就随便找个能下载的版本安装)下载XShell&#xff1a; XShell 家庭/学校免费版下载ubuntu操作系统 ubuntu-20.04.6-…...

使用 PaddleNLP 在 CPU(支持 AVX 指令)下跑通 llama2-7b或DeepSeek-r1:1.5b 模型(完成度80%)

原文&#xff1a;&#x1f6a3;‍♂️ 使用 PaddleNLP 在 CPU(支持 AVX 指令)下跑通 llama2-7b 模型 &#x1f6a3; — PaddleNLP 文档 使用 PaddleNLP 在 CPU(支持 AVX 指令)下跑通 llama2-7b 模型 &#x1f6a3; PaddleNLP 在支持 AVX 指令的 CPU 上对 llama 系列模型进行了…...

【Golang】第五弹----函数

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;Golang &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一、函数 1.1基本介绍…...

适合二次开发的Web组态软件推荐

在选择适合二次开发的Web组态软件时&#xff0c;需要考虑多个因素&#xff0c;包括开源与否、功能、社区支持、文档完整性等。以下是一些适合二次开发的Web组态软件&#xff1a; 1. Node-RED 简介: Node-RED 是一个基于流的编程工具&#xff0c;最初由IBM开发&#xff0c;现为…...

三、Docker 集群管理与应用

&#xff08;一&#xff09;项目案例 1、准备主机 &#xff08;1&#xff09;关闭防火墙&#xff0c;或者开放TCP端口2377&#xff08;用于集群管理通信&#xff09;、TCP/UPD端口7946&#xff08;用于节点之间的通信&#xff09;、UDP端口4789&#xff08;用于overlay网络流…...

Spring 注解解析

一、Import 1、核心作用 Import 是 Spring 模块化配置的核心注解&#xff0c;用于将外部配置类、组件或动态逻辑导入当前 Spring 上下文。其核心功能包括&#xff1a; 配置类聚合&#xff1a;整合多个分散的 Configuration 类&#xff0c;解决大型项目中配置分散的问题。动态…...

DeepSeek-R1思路训练多模态大模型-Vision-R1开源及实现方法思路

刚开始琢磨使用DeepSeek-R1风格训练多模态R1模型&#xff0c;就看到这个工作&#xff0c;本文一起看看&#xff0c;供参考。 先提出问题&#xff0c;仅靠 RL 是否足以激励 MLLM 的推理能力&#xff1f; 结论&#xff1a;不能&#xff0c;因为如果 RL 能有效激励推理能力&#…...

mysql select distinct 和 group by 哪个效率高

在有索引的情况下&#xff0c;SELECT DISTINCT和GROUP BY的效率相同&#xff1b;在没有索引的情况下&#xff0c;SELECT DISTINCT的效率高于GROUP BY‌。这是因为SELECT DISTINCT和GROUP BY都会进行分组操作&#xff0c;但GROUP BY可能会进行排序&#xff0c;触发filesort&…...

阿里云操作系统控制台评测:国产AI+运维 一站式运维管理平台

阿里云操作系统控制台评测&#xff1a;国产AI运维 一站式运维管理平台 引言 随着云计算技术的飞速发展&#xff0c;企业在云端的运维管理面临更高的要求。阿里云操作系统控制台作为一款集运维管理、智能助手和系统诊断等多功能于一体的工具&#xff0c;正逐步成为企业高效管理…...

Linux基础开发工具—vim

目录 1、vim的概念 2、vim的常见模式 2.1 演示切换vim模式 3、vim命令模式常用操作 3.1 移动光标 3.2 删除文字 3.3 复制 3.4 替换 4、vim底行模式常用命令 4.1 查找字符 5、vim的配置文件 1、vim的概念 Vim全称是Vi IMproved&#xff0c;即说明它是Vi编辑器的增强…...

11 应用层的域名知识点

一、DNS 1、理解 定义&#xff1a;DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;是互联网的一项核心服务&#xff0c;它将人类可读的域名&#xff08;也叫网址&#xff0c;如 www.example.com&#xff09;转换为机器可读的IP地址&#xff08;如 192.0.…...

5-24 色彩与风格——T2IA自适应

前言&#xff1a; 上一节我们介绍了ControlNet中的inpaint局部重绘 主要介绍ControlNet中的T2IA自适应。 色彩风格的参考和借鉴能力&#xff0c;有点类似于5-17 reference参考图 或者 5-16 画面风格迁移-shuffle洗牌 。当然在硬件的要求&#xff0c;软件的算法实现和使用方式…...

JAVA-Thread类实现多线程

引言&#xff1a; 本章博客涉及进程线程内容&#xff0c;如果不了解的可以看&#xff1a;什么是进程线程-CSDN博客 线程是操作系统的概念&#xff0c;操作系统提供的API供程序员使用操作。但是不同的操作系统(Winodws、Linux、Unix……差别很大),但是做为JAVA程序员就不需要担心…...

顺序表,单链表,双链表,循环链表(01星球)

文章目录 数据结构前导------C语言复习程序为什么要被编译器编译之后才能运行编译器把C语言程序转换成可以执行的机器码的过程做了什么宏定义typedef 关键字全局变量和局部变量常量字符的输入输出运算符冯诺依曼架构存储器容量数据类型指针指针本质为什么需要指针 数组数组指针…...

代码社区开源协议

开源协议是一种法律文件&#xff0c;用于规定开源软件的使用、修改和分发条件。它平衡了开发者和使用者的权益&#xff0c;同时推动开放协作与技术创新。以下是常见的开源协议及其特点和适用场景&#xff1a; 常见开源协议列表及介绍 1. MIT License 特点&#xff1a;非常宽…...

[免费]微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端+Vue管理端)(高级版)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端Vue管理端)(高级版)&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序(图书馆)自习室座位预约管理系统(SpringBoot后端Vue管理端)(高级版…...

树莓派:更新源

发行版本 Debian 一直维护着至少三个发行版本&#xff1a;“稳定版&#xff08;stable&#xff09;”&#xff0c;“测试版&#xff08;testing&#xff09;”和“不稳定版&#xff08;unstable&#xff09;”。 发行版目录 下一代 Debian 正式发行版的代号为 bullseye — 发布…...

树与二叉树的遍历

我们平时用的树都是二叉树 一、一些基础概念 1. 树就是一种&#xff1a;一对多的数据结构。树离不开递归&#xff0c;因为“树”就是“树”中有“树”。 二叉树就是 &#xff1a;空树 或者 每个结点的子结点个数小于等于2。 满二叉树&#xff1a; 除叶子结点外所有结点的…...

Web基础:HTML快速入门

HTML基础语法 HTML&#xff08;超文本标记语言&#xff09; 是用于创建网页内容的 标记语言&#xff0c;通过定义页面的 结构和内容 来告诉浏览器如何呈现网页。 超文本&#xff08;Hypertext&#xff09; 是一种通过 链接&#xff08;Hyperlinks&#xff09; 将不同文本、图像…...

异常(8)

今天补充一些异常的细节,帮助大家更好的理解异常. 注:关于异常的处理方式 异常的种类有很多,我们要根据不同的业务场景来决定. 对于比较严重的问题(例如和算钱相关的场景),应该让程序直接崩溃,防止造成更严重的结果 对于不太严重的问题(大多数场景),可以记录错误日志,并通过…...

平时作业

java作业 package zuoye; ​ public class zuoye02 {public static int Random(int n) {return (int)(n * Math.random());}public static void main(String[] args) {int n 100;//System.out.println(Random(n));int[]random new int[50];for(int i 0; i <50; i) {rand…...

宇树人形机器人开源模型

1. 下载源码 https://github.com/unitreerobotics/unitree_ros.git2. 启动Gazebo roslaunch h1_description gazebo.launch3. 仿真效果 H1 GO2 B2 Laikago Z1 4. VMware: vmw_ioctl_command error Invalid argument 这个错误通常出现在虚拟机环境中运行需要OpenGL支持的应用…...

**ResNet-SE + MFCC** 训练框架,包括 **数据加载、训练流程**,以及 **混淆矩阵** 可视化示例

1. 依赖库安装 如果你还没安装相关库&#xff0c;请先执行&#xff1a; pip install torch torchaudio torchvision scikit-learn matplotlib tqdm2. 数据加载 这里假设你有一个 音频分类数据集&#xff0c;其文件结构如下&#xff1a; dataset/ │── train/ │ ├──…...

Golang | 每日一练 (5)

&#x1f4a2;欢迎来到张胤尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 Golang | 每日一练 (5)题目参考答案线程与协程线程切换…...

搞定python之四----函数、lambda和模块

本文是《搞定python》系列专栏的第四篇&#xff0c;通过代码演示列python自定义函数、lambda和模块的用法。本文学习完成后&#xff0c;python的基础知识就完了。后面会学习面向对象的内容。 1、自定义函数 # 测试python自定义函数# 有参数&#xff0c;没有返回值 def say_he…...

算法分享———进制转换通用算法

模板一&#xff1a;任意&#xff08;K&#xff09;进制转10进制 将k进制的x转化为10进制的x ll x0; for(int i1;i<n;i) { xx*ka[i]; } cout<<x<<endl;模板二&#xff1a;十进制转m进制 ll x; cin>>x; while(x) { a[cnt]x%k; x/k; } reverse(a1,a1cnt);…...

Proser:新增指令批次发送功能

Proser中的批次发送功能&#xff0c;是通过指令集进行管理的。 起初设计时&#xff0c;希望指令集窗口自身包含指令的编辑功能&#xff0c;这部分功能与传输窗口的功能重合度高&#xff0c;所以设计上进行了简化&#xff0c;由用户在传输窗口输入指令&#xff0c;添加到指令集窗…...

rpc grpc

RPC Remote Procedure Call&#xff0c;远程过程调用&#xff0c;是用来屏蔽分布式计算中的各种调用细节&#xff0c;使得调用远端的方法就像调用本地的一样。 客户端与服务端沟通的过程 客户端发送数据(以字节流的方式)&#xff1b;&#xff08;编码&#xff09;服务端接受…...

AI赋能铁道安全巡检探索智能巡检新时代,基于YOLOv7全系列【tiny/l/x】参数模型开发构建铁路轨道场景下轨道上人员行为异常检测预警系统

在交通强国的战略引领下&#xff0c;中国铁路网如巨龙般纵贯大江南北&#xff0c;将五湖四海紧密相连&#xff0c;极大地促进了人员出行与物流运输的便捷性。然而&#xff0c;随着铁路线路的不断扩展&#xff0c;管理层面的安全问题也日益凸显。历史上&#xff0c;多起与铁路相…...

Kubernetes安全:集群保护的最佳实践

随着容器化技术的广泛应用&#xff0c;Kubernetes已经成为企业IT基础设施的重要组成部分。然而&#xff0c;Kubernetes集群的复杂性也带来了独特的安全挑战。如何在动态变化的云原生环境中保障集群的安全性&#xff0c;成为每一位运维工程师和安全专家关注的焦点。本文将详细探…...

R+VIC模型融合实践技术应用及未来气候变化模型预测

在气候变化问题日益严重的今天&#xff0c;水文模型在防洪规划&#xff0c;未来预测等方面发挥着不可替代的重要作用。目前&#xff0c;无论是工程实践或是科学研究中都存在很多著名的水文模型如SWAT/HSPF/HEC-HMS等。虽然&#xff0c;这些软件有各自的优点&#xff1b;但是&am…...

前端开发:混合技术栈的应用

目录 前言 混合技术栈的优势 移动端开发嵌入H5 1、场景描述 2、实现方法 3、源码示例 OC项目嵌入Swift的使用 1、场景描述 2、实现方法 3、源码示例 HarmonyOS开发中嵌入WebView 1、权限配置 2、加载网页 结束语 前言 随着技术的不断进步&#xff0c;软件开发领域…...