Android属性动画

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。

目录

  • 一、导读
  • 二、概览
  • 三、常用API
    • 3.1 ValueAnimator
    • 3.2 ObjectAnimator
    • 3.3 AnimatorSet
    • 插值器
  • 四、属性动画的使用
    • 4.1 xml中定义属性动画
    • 4.2 代码中定义属性动画
      • 4.2.1 使用 ValueAnimator 添加动画效果
      • 4.2.2 使用 ObjectAnimator 添加动画效果
        • 注意事项
      • 4.2.3 使用 AnimatorSet 编排多个动画
      • 4.2.4 动画监听器
      • 4.2.5 为 ViewGroup 对象的布局更改添加动画效果
      • 4.2.6 使用 StateListAnimator 为视图状态更改添加动画效果
      • 4.2.7 使用 TypeEvaluator
      • 4.2.8 指定关键帧
  • 五、 推荐阅读

在这里插入图片描述

一、导读

我们继续总结学习基础知识,温故知新。

二、概览

属性动画系统是一个强健的框架,用于为几乎任何内容添加动画效果。您可以定义一个随时间更改任何对象属性的动画,无论其是否绘制到屏幕上。
属性动画会在指定时长内更改属性(对象中的字段)的值。要添加动画效果,请指定要添加动画效果的对象属性,
例如对象在屏幕上的位置、动画效果持续多长时间以及要在哪些值之间添加动画效果。

借助属性动画系统,您可以定义动画的以下特性:

  • 时长:您可以指定动画的时长。默认时长为 300 毫秒。
  • 时间插值:您可以指定如何根据动画的当前已播放时长来计算属性的值。
  • 重复计数和行为:您可以指定是否在某个时长结束后重复播放动画以及重复播放动画多少次。您还可以指定是否要反向播放动画。如果将其设置为反向播放,则会先播放动画,然后反向播放动画,直到达到重复次数。
  • Animator 集:您可以将动画分成多个逻辑集,它们可以一起播放、按顺序播放或者在指定的延迟时间后播放。
  • 帧刷新延迟:您可以指定动画帧的刷新频率。默认设置为每 10 毫秒刷新一次,但应用刷新帧的速度最终取决于整个系统的繁忙程度以及系统为底层计时器提供服务的速度。

三、常用API

3.1 ValueAnimator

属性动画的主计时引擎,它也可计算要添加动画效果的属性的值。它具有计算动画值所需的所有核心功能,同时包含每个动画的计时详情、有关动画是否重复播放的信息、
用于接收更新事件的监听器以及设置待评估自定义类型的功能。为属性添加动画效果分为两个步骤:计算添加动画效果之后的值,以及对要添加动画效果的对象和属性设置
这些值。

ValueAnimator 不会重复,因此,您必须监听由 ValueAnimator 计算的值的更新情况,并使用您自己的逻辑修改要添加动画效果的对象。

3.2 ObjectAnimator

这是 ValueAnimator 的子类,用于设置目标对象和对象属性以添加动画效果
此类会在计算出动画的新值后相应地更新属性。在大多数情况下,您不妨使用 ObjectAnimator,因为它可以极大地简化对目标对象的值添加动画效果这一过程。不过,有时您需要直接使用 ValueAnimator,
因为 ObjectAnimator 存在其他一些限制,例如要求目标对象具有特定的访问器方法。

3.3 AnimatorSet

此类提供一种将动画分组在一起的机制,以使它们彼此相对运行。您可以将动画设置为一起播放、按顺序播放或者在指定的延迟时间后播放。

插值器

时间插值器指定了如何根据时间计算动画中的特定值。例如,您可以指定动画在整个动画中以线性方式播放,即动画在整个播放期间匀速移动;也可以指定动画使用非线性时间,
例如动画在开始后加速并在结束前减速。 下面表格 介绍了 android.view.animation 中包含的插值器。
如果下表提供的插值器都不能满足您的需求,请实现 TimeInterpolator 接口并创建您自己的插值器。

类/接口说明
AccelerateDecelerateInterpolator该插值器的变化率在开始和结束时缓慢但在中间会加快。
AccelerateInterpolator该插值器的变化率在开始时较为缓慢,然后会加快。
AnticipateInterpolator该插值器先反向变化,然后再急速正向变化。
AnticipateOvershootInterpolator该插值器先反向变化,再急速正向变化,然后超过定位值,最后返回到最终值。
BounceInterpolator该插值器的变化会跳过结尾处。
CycleInterpolator该插值器的动画会在指定数量的周期内重复。
DecelerateInterpolator该插值器的变化率开始很快,然后减速。
LinearInterpolator该插值器的变化率恒定不变。
OvershootInterpolator该插值器会急速正向变化,再超出最终值,然后返回。
TimeInterpolator该接口用于实现您自己的插值器。

四、属性动画的使用

可以在xml中定义,也可直接在代码中使用

4.1 xml中定义属性动画

  1. 新建目录及文件 res/animator/filename.xml

语法如下:

<setandroid:ordering=["together" | "sequentially"]>     指定此集合中动画的播放顺序,  sequentially	依序播放此集合中的动画。 together(默认)	同时播放此集合中的动画。<objectAnimatorandroid:propertyName="string"                     要添加动画效果的对象的属性,如"alpha" 或 "backgroundColor"android:duration="int"                            整数。动画的时间,以毫秒为单位。默认为 300 毫秒。android:valueFrom="float | int | color"           浮点数、整数或颜色。动画属性的起始值。如果未指定,则动画将从属性的 get 方法获得的值开始。颜色以六位十六进制数字表示,例如 #333333。android:valueTo="float | int | color"             浮点数、整数或颜色。必需。动画属性的结束值。颜色以六位十六进制数字表示,例如 #333333android:startOffset="int"                         整数。调用 start() 后动画延迟的毫秒数android:repeatCount="int"                         整数。动画的重复次数。设为 "-1" 表示无限次重复,也可设为正整数。例如,值 "1" 表示动画在初次播放后重复播放一次,因此动画总共播放两次。默认值为 "0",表示不重复。android:repeatMode=["restart" | "reverse"]        整数。动画播放到结尾处的行为。android:repeatCount 必须设置为正整数或 "-1",该属性才有效。设置为 "reverse" 可让动画在每次迭代时反向播放,设置为 "restart" 则可让动画每次从头开始循环播放。android:valueType=["intType" | "floatType"]/>     如果值为颜色,则不要指定此属性。动画框架会自动处理颜色值。  intType	指定动画值为整数。    floatType(默认)	指定动画值为浮点数。<animatorandroid:duration="int"                            整数。动画的时间,以毫秒为单位。默认为 300 毫秒。android:valueFrom="float | int | color"           浮点数、整数或颜色。必需。动画的起始值。颜色以六位十六进制数字表示,例如 #333333。android:valueTo="float | int | color"             浮点数、整数或颜色。必需。动画的结束值。颜色以六位十六进制数字表示,例如 #333333。android:startOffset="int"                         整数。调用 start() 后动画延迟的毫秒数。android:repeatCount="int"android:repeatMode=["restart" | "reverse"]android:valueType=["intType" | "floatType"]/><set>...</set>
</set>

其实也可以不用 set包裹,定义单一的动画

<objectAnimatorandroid:propertyName="string"android:duration="int"android:valueFrom="float | int | color"android:valueTo="float | int | color"android:startOffset="int"android:repeatCount="int"android:repeatMode=["restart" | "reverse"]android:valueType=["intType" | "floatType"]/>
<animatorandroid:duration="int"android:valueFrom="float | int | color"android:valueTo="float | int | color"android:startOffset="int"android:repeatCount="int"android:repeatMode=["restart" | "reverse"]android:valueType=["intType" | "floatType"]/>
  1. 资源引用:
    在 Java 或 Kotlin 代码中:R.animator.filename
    在 XML 中:@[package:]animator/filename

我们举例:
定义xml动画,然后在代码中调用开始动画。

<set android:ordering="sequentially"><set><objectAnimatorandroid:propertyName="x"android:duration="500"android:valueTo="400"android:valueType="intType"/><objectAnimatorandroid:propertyName="y"android:duration="500"android:valueTo="300"android:valueType="intType"/></set><objectAnimatorandroid:propertyName="alpha"android:duration="500"android:valueTo="1f"/>
</set>

开始动画

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.animator.property_animator);
set.setTarget(myObject);            // 必须操作
set.start();

4.2 代码中定义属性动画

4.2.1 使用 ValueAnimator 添加动画效果

借助 ValueAnimator 类,您可以为动画播放期间某些类型的值添加动画效果,只需指定一组要添加动画效果的 int、float 或颜色值即可。
您可以通过调用 ValueAnimator 的任一工厂方法来获取它:ofInt()、ofFloat() 或 ofObject()。例如:

    ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);animation.setDuration(1000);animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationResume(Animator animation) {}@Overridepublic void onAnimationPause(Animator animation) {}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {}});animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {// do something}});animator.setRepeatCount(2);animator.setRepeatMode(ValueAnimator.RESTART);animator.setInterpolator(interpolator);animation.start();

在上述代码中,当 start() 方法运行时,ValueAnimator 会开始计算 1000ms 时长内 0 和 100 之间的动画的值。

4.2.2 使用 ObjectAnimator 添加动画效果

ObjectAnimator 是上一部分中讨论的 ValueAnimator 的子类,它融合了 ValueAnimator 的计时引擎和值计算以及为目标对象的命名属性添加动画效果这一功能。
这可以极大地简化为任何对象添加动画效果的过程,因为动画属性会自动更新,因此您也无需再实现 ValueAnimator.AnimatorUpdateListener 了。

    ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "alpha", 0.3f, 1f);objectAnimator1.setDuration(1000);objectAnimator1.setRepeatCount(ValueAnimator.INFINITE);objectAnimator1.setRepeatMode(ValueAnimator.REVERSE);objectAnimator1.start();

上面的代码是修改view的透明度,看到构造方法里面的那个 “alpha” 了吧,我们在构造时,传入的对象,如上面的view,
必须包含有setAlpha()方法,否则设置是失败的,我们看view的源码,发现果然有

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) 还有很多其他的
public void setRotation(float rotation) 
public void setRotationX(float rotation) 
public void setRotationY(float rotation) 
public void setBackgroundColor(@ColorInt int color)
public void setScaleX(float scaleX)
public void setScaleY(float scaleX)
public void setTranslationX(float translationX)
public void setTranslationY(float translationX)
等等

所以可以有

ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 0f, xValue, 0f);ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "translationY", 0f, yValue, 0f);ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f, 1f, 0.95f);ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f, 1f, 0.95f);ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "rotation", 0.0F, 360f);等等

这里面的属性可以随意指定,只要我们要做动画的类中包含有该属性的set方法,例如:

public class Test {public final void setProcess(final float process) {}ObjectAnimator mProcessAnimator = ObjectAnimator.ofFloat(this, "process", 0, 0)
}
注意事项

要使 ObjectAnimator 正确更新属性,您必须执行以下操作:

  • 要添加动画效果的对象属性必须具有 set() 形式的 setter 函数(采用驼峰式大小写形式)。由于 ObjectAnimator 会在动画过程中自动更新属性,它必须能够使用此 setter 方法访问该属性。例如,如果属性名称为 foo,则需要使用 setFoo() 方法。如果此 setter 方法不存在,您有三个选择:
    • 如果您有权限,可将 setter 方法添加到类中。
    • 使用您有权更改的封装容器类,让该封装容器使用有效的 setter 方法接收值并将其转发给原始对象。
    • 改用 ValueAnimator。
  • 如果您在 ObjectAnimator 的一个工厂方法中仅为 values… 参数指定了一个值,则系统会假定它是动画的结束值。
    因此,要添加动画效果的对象属性必须具有用于获取动画起始值的 getter 函数。getter 函数必须采用 get() 形式。例如,如果属性名称为 foo,则需要使用 getFoo() 方法。
  • 要添加动画效果的属性的 getter(如果需要)和 setter 方法的操作对象必须与您为 ObjectAnimator 指定的起始值和结束值的类型相同。
    例如,如果构建以下 ObjectAnimator,则必须具有 targetObject.setPropName(float) 和 targetObject.getPropName(float):
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • 根据您要添加动画效果的属性或对象,您可能需要对视图调用 invalidate() 方法,以强制屏幕使用添加动画效果之后的值重新绘制自身。
    您可以在 onAnimationUpdate() 回调中执行此操作。例如,如果为可绘制对象的颜色属性添加动画效果,则仅当该对象重新绘制自身时,屏幕才会刷新。
    视图的所有属性 setter(如 setAlpha() 和 setTranslationX())都会使视图失效,因此,在使用新值调用这些方法时,您无需使视图失效。如需详细了解监听器,请参阅动画监听器部分。

4.2.3 使用 AnimatorSet 编排多个动画

使用AnimatorSet ,可以指定是同时播放动画、按顺序播放还是在指定的延迟时间后播放。还可以相互嵌套 AnimatorSet 对象。

举例:
以下代码段通过以下方式播放相应的 Animator 对象:

1、播放 bounceAnim。
2、同时播放 squashAnim1、squashAnim2、stretchAnim1 和 stretchAnim2。
3、播放 bounceBackAnim。
4、播放 fadeAnim。

    AnimatorSet bouncer = new AnimatorSet();bouncer.play(bounceAnim).before(squashAnim1);bouncer.play(squashAnim1).with(squashAnim2);bouncer.play(squashAnim1).with(stretchAnim1);bouncer.play(squashAnim1).with(stretchAnim2);bouncer.play(bounceBackAnim).after(stretchAnim2);ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);fadeAnim.setDuration(250);AnimatorSet animatorSet = new AnimatorSet();animatorSet.play(bouncer).before(fadeAnim);animatorSet.start();

下面同时播放3个动画

ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(view, "alpha", 0.3f, 1f);objectAnimator1.setDuration(1000);objectAnimator1.setRepeatCount(ValueAnimator.INFINITE);objectAnimator1.setRepeatMode(ValueAnimator.REVERSE);ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(view, "rotation", 0.0F, 360f);objectAnimator2.setDuration(5000);objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);AnimatorSet animatorSet = new AnimatorSet();animatorSet.setInterpolator(new LinearInterpolator());animatorSet.playTogether(objectAnimator1, objectAnimator2);animatorSet.start();

4.2.4 动画监听器

您可以使用下述监听器来监听动画播放期间的重要事件。

  • Animator.AnimatorListener

    • onAnimationStart() - 在动画开始播放时调用。
    • onAnimationEnd() - 在动画结束播放时调用。
    • onAnimationRepeat() - 在动画重复播放时调用。
    • onAnimationCancel() - 在动画取消播放时调用。取消的动画也会调用 onAnimationEnd(),无论它们以何种方式结束。
  • ValueAnimator.AnimatorUpdateListener

    • onAnimationUpdate() - 对动画的每一帧调用。监听此事件即可使用 ValueAnimator 在动画播放期间生成的计算值。要使用该值,请查询传递到事件中的 ValueAnimator 对象,
      以使用 getAnimatedValue() 方法获取当前添加动画效果之后的值。如果使用了 ValueAnimator,则必须实现此监听器。

4.2.5 为 ViewGroup 对象的布局更改添加动画效果

将 ViewGroup 的 android:animateLayoutchanges 属性设置为 true,将此属性设置为 true 可自动为添加到 ViewGroup 或从中删除的视图以及该 ViewGroup 中剩余的视图添加动画效果
eg:

    <LinearLayoutandroid:orientation="vertical"android:layout_width="wrap_content"android:layout_height="match_parent"android:id="@+id/verticalContainer"android:animateLayoutChanges="true" />

4.2.6 使用 StateListAnimator 为视图状态更改添加动画效果

使用根 元素和子 元素在 XML 资源中定义 StateListAnimator,每个元素都指定一个由 StateListAnimator 类定义的不同视图状态。每个 都包含一个属性动画集的定义。

例如,以下文件创建了一个状态列表 Animator,可在按下后更改视图的 x 和 y 比例:
res/xml/animate_scale.xml

    <?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- the pressed state; increase x and y size to 150% --><item android:state_pressed="true"><set><objectAnimator android:propertyName="scaleX"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1.5"android:valueType="floatType"/><objectAnimator android:propertyName="scaleY"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1.5"android:valueType="floatType"/></set></item><!-- the default, non-pressed state; set x and y size to 100% --><item android:state_pressed="false"><set><objectAnimator android:propertyName="scaleX"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1"android:valueType="floatType"/><objectAnimator android:propertyName="scaleY"android:duration="@android:integer/config_shortAnimTime"android:valueTo="1"android:valueType="floatType"/></set></item></selector>

要将状态列表 Animator 附加到视图,请添加 android:stateListAnimator 属性,如下所示:

    <Button android:stateListAnimator="@xml/animate_scale"... />

现在,当此按钮的状态发生变化时,会使用 animate_scale.xml 中定义的动画。

或者,如果要转为在代码中将状态列表 Animator 分配给视图,则可使用 AnimatorInflater.loadStateListAnimator() 方法,
然后使用 View.setStateListAnimator() 方法将 Animator 分配给相应视图。

您还可以使用 AnimatedStateListDrawable 在状态更改间播放可绘制动画,而不是为视图的属性添加动画效果。
Android 5.0 中的一些系统微件默认会使用这些动画。以下示例展示了如何将 AnimatedStateListDrawable 定义为 XML 资源:

    <!-- res/drawable/myanimstatedrawable.xml --><animated-selectorxmlns:android="http://schemas.android.com/apk/res/android"><!-- provide a different drawable for each state--><item android:id="@+id/pressed" android:drawable="@drawable/drawableP"android:state_pressed="true"/><item android:id="@+id/focused" android:drawable="@drawable/drawableF"android:state_focused="true"/><item android:id="@id/default"android:drawable="@drawable/drawableD"/><!-- specify a transition --><transition android:fromId="@+id/default" android:toId="@+id/pressed"><animation-list><item android:duration="15" android:drawable="@drawable/dt1"/><item android:duration="15" android:drawable="@drawable/dt2"/>...</animation-list></transition>...</animated-selector>

4.2.7 使用 TypeEvaluator

如果要为 Android 系统无法识别的类型添加动画效果,则可以通过实现 TypeEvaluator 接口来创建您自己的评估程序。
Android 系统可以识别的类型为 int、float 或颜色,分别由 IntEvaluator、FloatEvaluator 和 ArgbEvaluator 类型评估程序提供支持。

TypeEvaluator 接口中只有一种要实现的方法,那就是 evaluate() 方法。这样,您使用的 Animator 就会在动画的当前点为添加动画效果之后的属性返回适当的值。FloatEvaluator 类演示了如何做到这一点:

    public class FloatEvaluator implements TypeEvaluator {public Object evaluate(float fraction, Object startValue, Object endValue) {float startFloat = ((Number) startValue).floatValue();return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);}}

4.2.8 指定关键帧

Keyframe 对象由时间值对组成,用于在动画的特定时间定义特定的状态。每个关键帧还可以用自己的插值器控制动画在上一关键帧时间和此关键帧时间之间的时间间隔内的行为。

要实例化 Keyframe 对象,您必须使用它的任一工厂方法(ofInt()、ofFloat() 或 ofObject())来获取类型合适的 。然后,通过调用 ofKeyframe() 工厂方法来获取 PropertyValuesHolder 对象。
获取对象后,您可以通过传入 PropertyValuesHolder 对象以及要添加动画效果的对象来获取 Animator。以下代码段演示了如何做到这一点:

    Keyframe kf0 = Keyframe.ofFloat(0f, 0f);Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);Keyframe kf2 = Keyframe.ofFloat(1f, 0f);PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);rotationAnim.setDuration(5000);

动画

五、 推荐阅读

Java 专栏

SQL 专栏

数据结构与算法

Android学习专栏
ddd

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于AT89C52单片机的计算器设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/88637995?spm1001.2014.3001.5503 源码获取 B 源码仿真图课程设计51 摘 要 计算器一般是指“电子计算器”,能进行数学运算的手持机器&#xff0c;拥有集成电路芯…

广东高院严惩“套路贷”犯罪,保护校园安全

近日&#xff0c;广东高院发布了一批依法严惩“套路贷”犯罪的典型案例&#xff0c;其中一起涉及在校学生的“套路贷”案件引起了广泛关注。 这起案件中&#xff0c;张某等人针对在校大学生开展无抵押高息短期借款“套路贷”业务&#xff0c;通过频繁威胁恐吓、借新还旧、转单…

Linux:进程地址空间

目录 1.程序地址空间 2.进程地址空间 1.程序地址空间 我们在讲C/C语言的时候&#xff0c;32位平台下&#xff0c;我们见过这样的空间布局图 我们来验证一下这张图的正确性&#xff1a; int un_gval;int init_gval100;int main(int argc, char* argv[],char* env[]){//代码…

springMVC-模型数据的处理

一、数据放入到request域当中 1、把获取的数据放入request域中&#xff0c; 方便在跳转页面去显示 <a>添加主人信息</a> <form action"vote/vote04" method"post" >主人id&#xff1a;<input type"text" name"id&q…

Vue学习笔记-Vue3中的customRef

作用 创建一个自定义的ref&#xff0c;并对其依赖项的更新和触发进行显式控制 案例 描述&#xff1a;向输入框中输入内容&#xff0c;在下方延迟1秒展示输入内容 代码&#xff1a; <template><input type"text" v-model"keyword"><h3&…

设计模式——组合模式(结构型)

引言 组合模式是一种结构型设计模式&#xff0c; 你可以使用它将对象组合成树状结构&#xff0c; 并且能像使用独立对象一样使用它们。 问题 如果应用的核心模型能用树状结构表示&#xff0c; 在应用中使用组合模式才有价值。 例如&#xff0c; 你有两类对象&#xff1a; ​…

用23种设计模式打造一个cocos creator的游戏框架----(十五)策略模式

1、模式标准 模式名称&#xff1a;策略模式 模式分类&#xff1a;行为型 模式意图&#xff1a;定义一系列的算法&#xff0c;把它们一个个封装起来&#xff0c;并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化 结构图&#xff1a; 适用于&#xff1…

贝锐蒲公英解决方案:企业海外分部高效、稳定访问国内办公系统

某电气技术有限公司是一家专注数字电源研发、制造和销售的企业。公司致力于为大数据和新能源行业提供智慧能源解决方案, 数字电源产品在数据与算力中心、网络基础设施、电池储能换电、家庭能源系统中均有广泛应用。目前在国内以及东南亚、欧洲、美国等地设有分公司/办事处&…

STM32F407-14.3.18-01连接霍尔传感器

连接霍尔传感器 可通过用于生成电机驱动 PWM 信号的高级控制定时器&#xff08;TIM1 或 TIM8&#xff09;以及图 114 中称为 “接口定时器”的另一个定时器 TIMx&#xff08;TIM2、TIM3、TIM4 或 TIM5&#xff09;&#xff0c;实现与霍尔传感器的连接。3 个定时器输入引脚&…

Android动画(四)——属性动画ValueAnimator的妙用

目录 介绍 效果图 代码实现 xml文件 介绍 ValueAnimator是ObjectAnimator的父类&#xff0c;它继承自Animator。ValueAnimaotor同样提供了ofInt、ofFloat、ofObject等静态方法&#xff0c;传入的参数是动画过程的开始值、中间值、结束值来构造动画对象。可以将ValueAnimator看…

LOF基金跟股票一样吗?

LOF基金&#xff0c;全称为"上市型开放式基金"&#xff0c;是一种可以在上海证券交易所认购、申购、赎回及交易的开放式证券投资基金。投资者可以通过上海证券交易所场内证券经营机构或场外基金销售机构进行认购、申购和赎回基金份额。 LOF基金的特点是既可以像股票…

1852_bash中的find应用扩展

Grey 全部学习内容汇总&#xff1a; https://github.com/GreyZhang/toolbox 1852_bash中的find应用扩展 find这个工具我用了好多年了&#xff0c;但是是不是真的会用呢&#xff1f;其实不然&#xff0c;否则也不会出现这种总结式的笔记。其实&#xff0c;注意部分小细节之后…