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

Android 视图动画与属性动画的区别

Android的视图动画和属性动画在功能和使用上有一些明显的区别。

视图动画主要作用于视图,实现如缩放、旋转等效果。这种动画效果相对固定,只能应用于视图对象,且只能改变视图的大小和位置,而不能真正改变视图的属性。视图动画在Android 3.0以前的版本中广泛应用,但其在应用中的灵活性相对较低。

相比之下,属性动画在Android 3.0之后引入,其功能和灵活性都大大增强。属性动画可以对一个对象的属性进行操作,不仅能应用于视图对象,还能应用于任何对象。它不仅能实现缩放、旋转等效果,还能自定义动画效果,监听动画的过程,并在动画过程中或完成后执行特定的动作。属性动画通过改变对象的属性来实现动画,可以真正改变对象的属性。

总的来说,属性动画比视图动画更强大和灵活。它不仅可以实现视图动画的所有功能,还具有更多的自定义选项和更广泛的应用范围。

正文

我们知道视图动画并不能真正影响VIew的属性,而view的相对位置,大小等都是view的属性,所以视图动画并不能真正的改变view,所以属性动画便有了价值。同时之前的视图动画不能动态的改变背景颜色什么的,而属性动画却可以。下面我们来看属性动画的一些相关类:

  • ValueAnimator :Animator 的子类,实现了动画的整个处理逻辑,也是属性动画最为核心的类
  • ObjectAnimator:对象属性动画的操作类,继承自ValueAnimator,通过该类使用动画的形式操作对象的属性
  • TimeInterpolator:时间插值器,它的作用是根据时间流逝的百分比来计算当前属性值改变的百分比,系统预置的有线性插值器、加速减速插值器、减速插值器等。
  • TypeEvaluator:TypeEvaluator翻译为类型估值算法,它的作用是根据当前属性改变的百分比来计算改变后的属性值
  • Property:属性对象、主要定义了属性的set和get方法
  • PropertyValuesHolder:持有目标属性Property、setter和getter方法、以及关键帧集合的类。
  • KeyframeSet:存储一个动画的关键帧集

ValueAnimator

那么应该如何理解ValueAnimator呢?ValueAnimator可以看做一个动画时间值的处理分发器,他逻辑上并不直接操作view的属性。我们通过监听去获取到分发下来的值去对view进行操作,所以说,一个valueAnimator 分发下来的值只建议操作一个属性,写到一起也不是不行。那么如何获取到值的分发就很重要了。

ValueAnimator主要支持以下设置:

  • setDuration 设置动画执行时间。
  • setRepeatCount 重复次数 当等于ValueAnimator.INFINITE 表示循环。
  • setRepeatMode 设置循环播放模式,正序播放(RESTART)和逆序播放(REVERSE)。
  • setStartDelay 延时开始时间,第一次生效后,重复动画过程中将不再生效。
  • getAnimatedValue 获取当前运动点的值。
  • start 开始动画
  • cancel 取消动画
  • addUodateListenner 添加动画值的变化的监听。
  • addListener 添加动画监听。 开始start,结束end ,取消cancel,重复repeat
  • removeUpdateListener 移除更新值的监听,removeAllUpdateListeners 移除所有更新值的监听。
  • removelistener 移除动画监听,removeListeners 移除所有的动画监听
  • setStartDelay 延时多久开始动画,单位毫秒。
  • clone 完全克隆一个动画对象,包括他的所有设置及其监听器代码。

构造器

  • static ValueAnimator ofInt(int… values)
  • static ValueAnimator ofArgb(int… values)
  • static ValueAnimator ofFloat(float… values)
  • static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder… values)
  • static ValueAnimator ofObject(TypeEvaluator evaluator, Object… values)

可以看到入参都是多个。支持int,argb,float,PropertyValuesHolder,TypeEvaluator等类型。

如何实现视图动画的效果

我们知道,视图动画支持缩放scale、alpha 透明度、rotate旋转、translate平移。而ValueAnimator 主要是基于时间将我们设置到值进行分发,所以我们需要获取到每个片的值的改变。这个就是上面提到的addUodateListenner

translate 平移效果

我们知道,view的位置的决定是由layout(l,t,r,b) 个参数决定的。

  • l 视图的左边界相对于其父视图的位置。
  • t 顶部
  • r 右边
  • 底部

所以说,我们平移,就可以通过改变view.layout 中的值进行处理。

val animator=ValueAnimator.ofInt(0,400)
animator.duration = 1000
animator.addUpdateListener {val curValue :Int= it.animatedValue as Intbinding.btn1.layout(curValue,0,curValue+binding.btn1.width,binding.btn1.height)
}
animator.start()

上面的代码,我们将一个view 在X轴方向上,从0移动到400px 的位置。整个动画耗时1秒。下面代码也是平移:

val animator=ValueAnimator.ofInt(0,400)
animator.duration = 1000
animator.addUpdateListener {val curValue :Int= it.animatedValue as Intbinding.btn1.translationX=curValue.toFloat()
}
animator.start()

那么平移还有没有其他思路,我们知道view 还有一个滚动函数。如果说是平移内容,跑马灯效果,那么就可以调用scrollTo 函数。

scale 缩放

view 也提供了scale 函数用于缩放view。那么我们尝试将整个view在1秒内从1变化到2.

        val animator=ValueAnimator.ofFloat(1f,2f)animator.duration = 1000animator.addUpdateListener {val curValue :Float= it.animatedValue as Floatbinding.btn1.scaleX=curValue}animator.start()

可以看到,我们只是缩放了X轴,并没有缩放Y轴,缩放Y轴则是调用scaleY

roate 旋转

view 提供了rotation、rotationX、rotationY

        val animator=ValueAnimator.ofFloat(0f,360f)animator.duration = 1000animator.addUpdateListener {val curValue :Float= it.animatedValue as Float//binding.btn1.rotation=curValuebinding.btn1.rotationX=curValue//binding.btn1.rotationY=curValue}animator.start()

可以看到,上面的代码,我们围绕X轴进行了翻转360度。

alpha 透明度

改变透明度分为改变整个view的透明度和改变view 背景的透明度。

val animator=ValueAnimator.ofFloat(1f,0f,1f)
animator.duration = 3000
animator.addUpdateListener {val curValue :Float= it.animatedValue as Floatbinding.btn1.alpha=curValue
}
animator.start()

可以看到,上面代码是将一个view的透明度从1改变到0完全透明在到1完全不透明。

        val animator=ValueAnimator.ofFloat(255f,0f,255f)animator.duration = 3000animator.addUpdateListener {val curValue :Float= it.animatedValue as Floatbinding.btn1.background.alpha=curValue.toInt()}animator.start()

上面代码是将view的背景从完全不透明改到完全透明,再到完全不透明。

改变颜色

我们将按钮的颜色由黑色变化到红色。

    val animator=ValueAnimator.ofArgb(Color.BLACK,Color.RED)animator.duration = 1000animator.addUpdateListener {val curValue :Int= it.animatedValue as Intbinding.btn1.setTextColor(curValue)}animator.start()
}
总结

可以看到,我们上面的几乎的所有写法都是基于addUpdateListener,然后去改变view的属性。所以说,限制我们的全是想象力。这个动画只要view属性支持,我们就可以整出各种花样来。

自定义插值器与evaluator

我们在视图动画里面,知道Android 系统给我们提供了很多插值器。哪些插值器,在属性动画中同样可用。默认的插值器是LinearInterpolator。

自定义插值器

可以看懂LinearInterpolator 继承于BaseInterpolator。最终可以看到都是继承于TimeInterpolator,而这个接口只有一个函数。

float getInterpolation(float input);

而LinearInterpolator 则是原封不动的将input 给返回了,所以说,自定义插值器其实是对于input 进行计算,然后返回。在这个接口的描述中我们知道 input 的取值范围是0到1。这个用于表示动画执行时间的百分比。所以这个干预的是动画的时间。

evaluator

通过自定义插值器的描述,我们可以知道,插值器只是对于动画时长的处理。但是我们通过构造器,发现可以传入很多种类型,而对不同类型的值的分发,就靠evaluator了。所以不同的值类型有自己的evaluator.所有的evaluator都实现 TypeEvaluator 接口。默认的有:

  • IntEvaluator
  • FloatEvaluator
  • ArgbEvaluator

这个干预的是动画分发下来的值。我们看下IntEvaluator的实现代码:

public Integer evaluate(float fraction, Integer startValue, Integer endValue) {int startInt = startValue;return (int)(startInt + fraction * (endValue - startInt));
}

他是开始位置+百分比*(结束位置-开始位置)。所以,evaluate会调用多次。

使用ofObject 分发想要的内容

比如说,有一个需求,分发A到Z,因为涉及到动画,所以考虑写到动画里面。那么结合上面的知识,我们就需要自定义一个Evaluator.结合IntEvaluator 的经验。这里又一个知识点。就是每个char都有一个ASCII码,所以我们通过ASCII 码进行计算。

class CharEvaluator : TypeEvaluator<Char> {override fun evaluate(fraction: Float, startValue: Char, endValue: Char): Char {val start = startValue.codeval end = endValue.codeval cur = start + fraction * (end - start)return cur.toInt().toChar()}
}

class CharEvaluator : TypeEvaluator<Char> {override fun evaluate(fraction: Float, startValue: Char, endValue: Char): Char {val start = startValue.codeval end = endValue.codeval cur = start + fraction * (end - start)return cur.toInt().toChar()}
}

propertyValuesHolder与关键帧KeyFrame

构造器里面有一个 **static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder… values) ** 。通过阅读ValueAnimator 源码可以发现,几乎所有的构造器都会生成一个ProPertyValuesHolder 对象,这个对象其中保存了动画过程中需要操作的属性和对应的值。所以我们可以根据这个对象构造动画,大致分为一下几个大类。

  • ofFloat
  • ofint
  • ofKeyFrame,关键帧
  • ofMultFloat
  • ofMultInt
  • ofObject

当然包含了不同入参的重载函数,可以看到propertyValuesHolder是允许传入多个的,我使用ofInt 等每次都只能生成一个PropertyValuesHolder。

val animator=ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder.ofFloat("a",0f,10f),PropertyValuesHolder.ofInt("b",1,50),PropertyValuesHolder.ofInt("c",100,50))
animator.duration = 1000
animator.addUpdateListener {LogUtils.e("${it.getAnimatedValue("a")} ${it.getAnimatedValue("b")} ${it.getAnimatedValue("c")}   ")
}
animator.start()

当我们设置多个Holderd的时候,可以调用 **Object getAnimatedValue(String propertyName) ** 获取对应的value。如果只有一个值,默认去的第一个,所以 it.animatedValue 就可以获取到。当然一个值也可以传递propertyName 进行获取。

keyFrame 关键帧

我们想要控制动画的速率的变化,可以通过自定义插值器或者自定义Evaluator实现。但是这个涉及到数学知识,为了更方便的解决控制动画速率的问题,Google提供了一个新的思路,Keyframe,这个和帧动画的概念类似,动画将由具体帧决定,而不是计算。而Keyframe 则依旧和ValueAnimator一样,操作的是数据。可以看到keyframe 依旧支持3种类型的重载:

  • ofFloat
  • ofInt
  • ofObject

入参:

  • fraction 表示当前显示的进度,即插值器中getInterpolation 函数的返回值。
  • value 表示动画当前所在的数值位置,即animateValue .

例如:keyFrame.ofFloat(0.25f,25) 表示动画进度是百分之25,数值是25。

val animator=ValueAnimator.ofPropertyValuesHolder(PropertyValuesHolder.ofKeyframe("a",Keyframe.ofInt(0f,0),Keyframe.ofInt(0.25f,25),Keyframe.ofInt(0.50f,50),Keyframe.ofInt(0.75f,75),Keyframe.ofInt(1f,100),))
animator.duration = 1000
animator.addUpdateListener {LogUtils.e("${it.getAnimatedValue("a")} ")
}
animator.start()

通过Log可以看到,这个同样包含匀速的插值器,所以这个也可以设置插值器。和之前的逻辑是一致的,values 的值必须大于等于2,必须保证有一个开始和一个结束,所以Keyframe 必须大于等于2。

ObjectAnimator

通过上面的例子,我们可以看到,ValueAnimator 只是对值进行了分发,一些属性的设置还需要我们自己写,于是就产生了ObjectAnimator类。结合ValueAnimator 实现动画的经验,ObjectAnimator 其实也就是在addUpdateListener 中帮助我们调用了函数,默认帮我们拼接了set,所以这个应该是反射实现的。

淡入淡出

            ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(binding.image, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);alphaAnim.setDuration(3000);alphaAnim.start();

旋转

            // 旋转ObjectAnimator anim = ObjectAnimator.ofFloat(binding.image, "rotation", 0f, 360f);// 动画时长anim.setDuration(1000);anim.start();

缩放

            ObjectAnimator anim = ObjectAnimator.ofFloat(binding.image, "scaleX", 1.0f, 1.5f);anim.setDuration(1000);anim.start();

平移

            ObjectAnimator transXAnim = ObjectAnimator.ofFloat(binding.image, "translationX", 100, 400);transXAnim.setDuration(3000);transXAnim.start();

组合同时缩放X与Y

            AnimatorSet set = new AnimatorSet();ObjectAnimator animX = ObjectAnimator.ofFloat(binding.image, "scaleX", 1.0f, 1.5f);ObjectAnimator animY = ObjectAnimator.ofFloat(binding.image, "scaleY", 1.0f, 1.5f);// 同时动set.playTogether(animX, animY);set.setDuration(3000);set.start();

组合顺序缩放X与Y

            AnimatorSet set = new AnimatorSet();ObjectAnimator animX = ObjectAnimator.ofFloat(binding.image, "scaleX", 1.0f, 1.5f);ObjectAnimator animY = ObjectAnimator.ofFloat(binding.image, "scaleY", 1.0f, 1.5f);// 按照顺序动set.playSequentially(animX, animY);set.setDuration(3000);set.start();

view 生命周期绑定动画

这么写的好处就是view 移除出屏幕就暂停动画了。而且便于recyclerview的复用

 binding.image.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {@Overridepublic void onViewAttachedToWindow(View v) {// TODO 设置动画 }@Overridepublic void onViewDetachedFromWindow(View v) {v.clearAnimation();}});
自定义属性与ofObject(Object target, String propertyName,
        TypeEvaluator evaluator, Object... values)

那么,当我们需要调用view的自定义函数呢?那么就需要使用这个函数了。还是上面的哪例子,我们A到Z,设置为text。这个时候,就需要用到反射的相关知识了,setText 的入参类型是CharSequence,但是它是通过values去获取到对应的class的,但是我们传入的参数是CharSequence的实现类,所以,基于values 是永远拿不到void setText(CharSequence text)这个函数的。但是我们可以偷换概念。既然65是ASCII码的A,那么我们就用int,然后自己写一个int 入参的函数调用setText.

val animator=  ObjectAnimator.ofObject(this,"Text",IntEvaluator(),65,75)animator.duration=1000animator.start()

fun setText(code:Int){binding.btn1.text = code.toChar().toString()
}

当然。写一个入参类型是string 的方法也行。

组合动画 AnimatorSet

因为ValueAnimator 需要自己绑定属性,那么我们做动画的大多数都是基于ObjectAnimator。

  • playAwquentially 动画依次执行。
  • playTogether 动画一起执行。
  • setDuration 单个动画的时长,优先级高于子动画的时长。
  • setInterPolator 插值器,优先级高于子动画。
  • setTarget 目标动画,这个优先级也高于子动画。
  • setStartDelay 设置延时开始动画时长,仅争对AnimatorSet的激活时长,对单个动画的延时设置没有影响。

我们知道动画是否循环播放是又动画本身控制的。所以AnimatorSet 不参与动画循环播放的控制。

animatorSet.builder

用于更精细化的控制组合动画的播放。

  • play 播放那个动画
  • with 和前面动画一起播放。
  • before 先执行这个动画,再执行前面的动画。
  • after 前面的动画执行完成后,才执行这个动画
  • after 延迟n毫秒后执行动画。
animatorSet 监听器AnimatorListener
  • onAnimationStart 开始
  • end 结束
  • cancel 取消
  • repeat 重复

ViewPropertyAnimator

通过ObjectAnimator 可以便捷的设置属性动画,那么还有没有更便捷的呢?那就是ViewPropertyAnimator。

binding.btn1.animate().setDuration(1000).translationX(10f).rotationX(360f).start()

因为这个并没有像ObjectAnimator 一样使用反射,而是通过计算出具体的的属性值,然后调用invalidata() 函数进行重绘,性能是要比ObjectAnimator 高一些,但是反射的性能影响微乎其微,所以他的优势是链式调度与简化了代码的读写。

在xml中的实现

如何通过XML 实现ValueAnimator,ObjectAnimator,AnimatorSet。我们通常不使用ValueAnimator,而是使用ObjectAnimator。

ValueAnimator

对应的标签为animator。通过animatorInflater.loadAnimator() 获取xml中的属性动画。

  • duration 动画时长。
  • valueFrom 初始动画的值,为float,int和color种类型。
  • valueTo 同样3个类型的值。
  • startOffset 动画激活延时,单位毫秒。
  • repeatConunt 重复次数,infinite 表示无限循环
  • repeatMode 重复模式。repeat 正序,reverse 倒序。
  • valueType 表示数值类型,和to、from 对应,如果是color 就不需要设置这个值。
  • interpolator 设置插值器。

objectAnimator 标签

和animator 标签类似,只是多了一个属性:

  • propertyName 对应要操作的属性的名称。

set标签

这个在属性动画中特指animatorSet,用于实现多个属性动画的组合。

总结

整体的属性动画都是还是基于一个分发器和操作view的属性去实现的。通常而言,还是写到代码里面的时候居多,而且通过ViewPropertyAnimator也可以实现一些简单的组合动画什么的。

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

相关文章:

Android 视图动画与属性动画的区别

Android的视图动画和属性动画在功能和使用上有一些明显的区别。 视图动画主要作用于视图&#xff0c;实现如缩放、旋转等效果。这种动画效果相对固定&#xff0c;只能应用于视图对象&#xff0c;且只能改变视图的大小和位置&#xff0c;而不能真正改变视图的属性。视图动画在A…...

Springboot——jxls实现同sheet多个列表展示

文章目录 前言制定模板1、限定模板数据的范围2、设定报表展示项 编写测试类1、将xls模板文件放于 resource 下的 doc文件夹中2、导入依赖文件3、编写接口和导出逻辑 效果预览结论 前言 在之前的博客中Springboot——使用jxls实现excel模板导出excel&#xff0c;具体说明了jxls…...

分布式软件架构——服务端缓存的三种属性

服务端缓存 在透明多级分流系统中&#xff0c;我们以流量从客户端中发出开始&#xff0c;以流量到达服务器集群中真正处理业务的节点结束。一起探索了在这个过程中与业务无关的一些通用组件&#xff0c;包括DNS、CDN、客户端缓存&#xff0c;等等。 实际上&#xff0c;服务端缓…...

Flink之Watermark策略代码模板

方式作用WatermarkStrategy.noWatermarks()不生成watermarkWatermarkStrategy.forMonotonousTimestamps()紧跟最大事件时间watermark生成策略WatermarkStrategy.forBoundedOutOfOrderness()允许乱序watermark生成策略WatermarkStrategy.forGenerator()自定义watermark生成策略 …...

ubuntu 安装postgresql,增加VECTOR向量数据库插件 踏坑详细流程

PGSQL安装&#xff0c;删除&#xff0c;运行&#xff0c;修改密码流程 Ubuntu18.04安装与配置postgresql含远程连接教程&#xff08;含踩坑记录&#xff09;_sudo apt-get install postgresql-CSDN博客 详细安装流程以上博客&#xff0c;自己也记录下 安装vector扩展连接 声明…...

基于Springboot实现影视影院订票选座管理系统【项目源码+论文说明】分享

基于Springboot实现影视影院订票选座管理系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个影城管理系统 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论…...

mysql批量插入数据,跳过唯一索引报错

数据准备 DROP TABLE IF EXISTS user1; CREATE TABLE user1 ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(45) NULL, age INT(3) NOT NULL, PRIMARY KEY (id), UNIQUE INDEX u_name (name));insert into user1(name, age) values (zhangshan, 18), (lisi, 19);1. INSERT I…...

论文阅读--Energy efficiency in heterogeneous wireless access networks

异构无线接入网络的能源效率 论文信息&#xff1a;Navaratnarajah S, Saeed A, Dianati M, et al. Energy efficiency in heterogeneous wireless access networks[J]. IEEE wireless communications, 2013, 20(5): 37-43. I. ABSTRACT && INTRODUCTION 本文提出了无…...

Redis的C客户端(hiredis库)使用

文章目录 1、Ubuntu安装redis服务端2、hiredis库的安装3、同步API接口的使用3.1、连接redis数据库redisConnect3.2、发送需要执行的命令redisCommand3.3、redisCommandArgv函数3.4、redisAppendCommand*函数支持管道命令3.5、释放资源3.6、同步连接代码 3.7、异步连接4、redis连…...

光引擎、光模块、光器件之间的关系和区别

最近小编有收到一些用户问“光引擎、光模块、光器件之间的关系和区别&#xff1f;”&#xff0c;众所周知光通信技术一直在不断演进&#xff0c;为满足不断增长的数据传输需求提供了强大的解决方案。而光通信系统中&#xff0c;光引擎、光模块和光器件是关键的组成部分&#xf…...

【办公-excel】两个时间相减 (二) - 带毫秒的时间进行相减操作

一、使用内部函数 1.1 效果展示 TEXT(((RIGHT(TEXT(B2,"yyyy-mm-dd hh:mm:ss.000"),LEN(TEXT(B2,"yyyy-mm-dd hh:mm:ss.000"))-FIND(".",TEXT(B2,"yyyy-mm-dd hh:mm:ss.000")))-RIGHT(TEXT(A2,"yyyy-mm-dd hh:mm:ss.000"),…...

二次封装View Design的table组件,实现宽度自适应,内容在一行展示

由于table组件本身并不支持宽度自适应&#xff0c;但实际项目需要&#xff0c;而且多处有用到table组件&#xff0c;所以尝试着自己来二次封装一下组件 想法 刚开始的想法很简单&#xff0c;就是获取每一列中数据和标题在表格中的长度&#xff0c;然后将当中最大的长度作为该列…...

Node.js代码漏洞扫描工具介绍——npm audit

npm audit 运行安全检查 主要作用&#xff1a;检查命令将项目中配置的依赖项的描述提交到默认注册中心&#xff0c;并要求报告已知漏洞。如果发现任何漏洞&#xff0c;则将计算影响和适当的补救措施。如果 fix 提供了参数&#xff0c;则将对包树应用补救措施。 具体参考&#x…...

node.js知识系列(3)-每天了解一点

目录 1. Express.js 中的中间件2. 处理路由和请求3. RESTful 路由4. 身份验证和授权5. 视图引擎6. 错误处理中间件7. 文件上传处理8. Cookie 和 Session 管理9. 路由参数和查询参数10. 处理跨域请求&#xff08;CORS&#xff09; &#x1f44d; 点赞&#xff0c;你的认可是我创…...

Zabbix监控系统 自定义监控项、自动发现与自动注册

Zabbix监控系统 自定义监控项、自动发现与自动注册 一、自定义监控内容部署实例二、zabbix 自动发现与自动注册部署实例2.1 部署zabbix自动发现 一、自定义监控内容部署实例 案列&#xff1a;自定义监控客户端服务器登录的人数 需求&#xff1a;限制登录人数不超过 3 个&#…...

Python信号之分享

在了解了Linux的信号基础之后&#xff0c;Python标准库中的signal包就很容易学习和理解。signal包负责在Python程序内部处理信号&#xff0c;典型的操作包括预设信号处理函数&#xff0c;暂停并等待信号&#xff0c;以及定时发出SIGALRM等。要注意&#xff0c;signal包主要是针…...

环信web、uniapp、微信小程序SDK报错详解---登录篇

项目场景&#xff1a; 记录对接环信sdk时遇到的一系列问题&#xff0c;总结一下避免大家再次踩坑。这里主要针对于web、uniapp、微信小程序在对接环信sdk时遇到的问题。主要针对报错400、404、401、40 (一) 登录用户报400 原因分析&#xff1a; 从console控制台输出及networ…...

DAZ To UMA⭐五.模型在Blender中的配置教程

文章目录 🟥 创建符合UMA的材质球属性1️⃣ 合并材质球🎁 选择材质球🎁 合并材质球🎁 删除多余材质球2️⃣ 将身体按材质球拆分🎁 进入身体编辑模式🎁 全选身体🎁 按材质分割身体🎁 重命名不同部位3️⃣ 将其余部位进行拆分🟧 更正选择缩放🟩 更新骨骼结构…...

网络安全工具汇总

网络安全工具汇总 1. 前言1.1. 工具提供 2. 漏洞库3. 杂项3.1. topology-scanner3.2. MDUT3.3. 404 4. 插件工具4.1. 浏览器插件4.1.1. Heimdallr4.1.2. HackTools4.1.3. SwitchyOmega4.1.4. fofa_view4.1.5. mitaka 4.2. CS插件4.2.1. taowu-cobalt_strike4.2.2. OLa4.2.3. Z1…...

day-65 代码随想录算法训练营(19)图论 part 04

463.岛屿的周长 分析&#xff1a; 1.陆地的旁边是海面&#xff0c;存在周长2.陆地在边界上&#xff0c;存在周长 思路一&#xff1a;深度优先遍历 1.通过记录访问情况来访问数据 class Solution { public:int direct[4][2]{{0,1},{0,-1},{1,0},{-1,0}};int res0;void dfs(…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...