Android 动画深度解析

news2024/12/20 14:06:23

一、Android 动画发展历程与核心类型总览

自 Android 诞生起,动画系统便不断推陈出新。早期存在补间动画(Tween Animation)与帧动画(Frame Animation),而 Android 3.0 重磅引入属性动画(Property Animation),极大地拓展了动画创作的边界。此外,Android 4.4(API level 19)又带来了转场动画(Transition Animation),进一步丰富了动画体系。这些动画类型在不同场景下各显神通,共同铸就了 Android 生动且富有交互性的用户界面体验,在 SDK 中它们分别对应着 Property Animation、View Animation(涵盖补间动画与帧动画)以及 Transition Animation。

二、动画资源分类、特性与实现全方位解读

(一)属性动画(Property Animation)

属性动画无疑是 Android 动画家族中最为强大且灵活的成员。它突破了传统动画仅针对 View 组件的局限,能够对任何对象的属性施展动画魔法,无论是位置、大小、透明度,还是自定义对象的特有属性,皆可在其掌控之下实现平滑自然的变化。其核心依托于 Animator 类族,其中 ObjectAnimator 与 ValueAnimator 尤为关键。

  • ObjectAnimator:此乃便捷之选,可直接针对目标对象的指定属性进行操作,开发者只需指明目标对象、属性名称以及动画的起始与结束值,ObjectAnimator 便能自动完成剩余的动画构建与执行工作。例如,若要使一个 View 的透明度从 1.0 渐变至 0.0,仅需如下代码:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.0f);
animator.setDuration(1000);
animator.start();

上述代码瞬间创建出一个时长 1000 毫秒的透明度渐变动画,并即刻启动。

  • ValueAnimator:相对而言更为底层,它专注于数值的生成与变化,并不直接关联特定对象的属性。开发者需自行监听其数值变化,并适时将这些变化手动应用于目标对象之上。这种方式虽略显繁琐,但却赋予了开发者对动画过程更精细的控制能力,适用于那些对动画数值变化逻辑有着特殊需求的场景。例如:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 100f);
valueAnimator.setDuration(2000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float value = (float) animation.getAnimatedValue();
        // 将 value 应用到目标对象的相关属性上,如位置、大小等
    }
});
valueAnimator.start();

在此示例中,ValueAnimator 首先生成从 0 到 100 的数值变化,开发者在监听器中获取这些数值,并根据需求应用到目标对象,实现自定义的动画效果。

属性动画的定义方式极为灵活,既可以借助 XML 进行声明式配置,也可运用 Java 或 Kotlin 代码以编程方式构建,开发者可依据项目的规模、复杂度以及个人偏好灵活抉择。

(二)视图动画(View Animation)

视图动画作为元老级的动画形式,主要聚焦于 View 组件的视觉变换,细分为补间动画(Tween Animation)与帧动画(Frame Animation)两类。

  • 补间动画(Tween Animation):通过对 View 的透明度、位置、大小和旋转角度等属性进行插值计算,从而在起始与结束状态之间自动生成平滑过渡的动画效果。其包含以下几种经典类型:
    • AlphaAnimation:专注于透明度的动态变化,例如从完全不透明到若隐若现的渐变,轻松营造出淡入淡出的视觉特效。
    • TranslateAnimation:负责掌控 View 在二维平面内的位置移动,无论是水平滑动、垂直升降,还是斜线漂移,皆能精准实现。
    • ScaleAnimation:专注于 View 尺寸的缩放操作,可实现等比例放大缩小,或者在 X、Y 方向上的独立缩放,为元素的强调或隐藏提供生动的表现手段。
    • RotateAnimation:围绕指定的旋转中心,使 View 按设定的角度进行旋转,无论是顺时针的优雅转动,还是逆时针的灵动回旋,均可随心所欲。

补间动画通常借助 XML 文件进行定义,这些 XML 文件需存放于 /res/anim/ 目录之下,如此可使动画的定义与代码逻辑分离,增强代码的可读性与可维护性。当然,使用 Java 或 Kotlin 代码创建补间动画亦不在话下。以下是一个 XML 定义补间动画的示例:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:duration="1000">
    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"/>
    <translate android:fromXDelta="0" android:toXDelta="100"/>
</set>

此 XML 定义了一个时长 1000 毫秒的动画组合,包含透明度从 1.0 到 0.0 的渐变以及在 X 方向上从 0 到 100 像素的位移。在代码中加载并应用该动画的方式如下:

Animation animation = AnimationUtils.loadAnimation(context, R.anim.custom_animation);
view.startAnimation(animation);
  • 帧动画(Frame Animation):以一种更为直观且简单的方式构建动画,它将一系列预先准备好的静态图像按顺序依次播放,从而形成连续的动画效果。其实现基于 AnimationDrawable 类,所有参与动画的图像资源需在 /res/drawable/ 目录下的 XML 文件中精心定义。例如:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="false">
    <item android:drawable="@drawable/frame1" android:duration="100"/>
    <item android:drawable="@drawable/frame2" android:duration="100"/>
    <item android:drawable="@drawable/frame3" android:duration="100"/>
    <!-- 更多帧图像资源依次罗列 -->
</animation-list>

在上述示例中,定义了一个循环播放的帧动画,每帧图像的显示时长均为 100 毫秒。在代码中启动该帧动画的操作如下:

ImageView imageView = findViewById(R.id.imageView);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();

(三)转场动画(Transition Animation)

转场动画的使命在于精心描绘界面状态之间的无缝切换过程,尤其在 Activity 或 Fragment 相互更替时大放异彩。它具备自动捕捉布局变化的神奇能力,并据此生成如丝般顺滑的过渡效果,让用户界面的切换显得自然流畅,毫无突兀之感。其核心组件包括 Scene、TransitionManager 和 Transition。

  • Scene:如同舞台上的一幕场景,它精准代表了一个特定的用户界面配置。开发者可依据不同的界面状态创建多个 Scene,每个 Scene 对应着独特的布局结构与视图组合。
  • TransitionManager:作为转场动画的导演,它肩负着统筹管理从一个 Scene 到另一个 Scene 华丽转变的重任。通过其提供的 API,开发者能够轻松触发场景之间的切换,并指定相应的过渡动画。
  • Transition:此乃定义两个场景之间动画行为的灵魂所在,它明确规定了在场景切换过程中,视图如何进行移动、缩放、淡入淡出等具体动画操作。例如,ChangeBounds 过渡可实现视图边界的平滑变化,Fade 过渡能够控制视图的透明度渐变,而 Slide 过渡则可使视图沿着指定方向滑动进入或离开屏幕。

以下是一个转场动画的示例代码:

// 定义开始和结束场景
Scene sceneStart = Scene.getSceneForLayout(sceneRoot, R.layout.scene_start, this);
Scene sceneEnd = Scene.getSceneForLayout(sceneRoot, R.layout.scene_end, this);

// 创建一个 ChangeBounds 转换
Transition transition = new ChangeBounds();
transition.setDuration(500); // 设置动画持续时间为 500 毫秒

// 执行转换
TransitionManager.go(sceneEnd, transition);

在上述示例中,首先创建了起始场景 sceneStart 和结束场景 sceneEnd,然后构建了一个 ChangeBounds 过渡动画,设定时长为 500 毫秒,最后借助 TransitionManager 启动从起始场景到结束场景的转场动画,期间视图的边界将以动画形式平滑过渡。

三、动画插值器(Interpolators):动画节奏的魔法棒

动画插值器堪称动画的灵魂调音师,它精心雕琢着动画进度的时间曲线,赋予动画千变万化的节奏韵律。Android 为开发者提供了丰富多样的插值器选择,每一种都能营造出截然不同的动画效果:

  • LinearInterpolator:秉持线性均匀变化的原则,动画如匀速行驶的列车,自始至终以恒定速度平稳推进,毫无波澜起伏,适用于那些对节奏稳定性要求极高的动画场景,如精确的进度条填充动画。
  • AccelerateDecelerateInterpolator:先缓缓加速,似初出茅庐者逐渐崭露头角,而后缓缓减速,如功成名就者低调归隐,整个过程恰似优雅的钟摆运动,起始与结束阶段平稳舒缓,中间阶段活力迸发,常用于模拟具有弹性和自然感的物理运动,如物体的自由落体与反弹。
  • AccelerateInterpolator:以慢热开场,随后如脱缰之马加速狂奔,将动画的张力逐渐释放,可生动地表现出物体由静止迅速转为高速运动的过程,如火箭发射时的加速升空,为动画注入强烈的紧迫感和冲击力。
  • DecelerateInterpolator:与 AccelerateInterpolator 恰恰相反,它以风驰电掣之势开局,而后逐渐收敛锋芒,缓缓减速直至停止,仿佛高速行驶的汽车逐渐刹车停靠,常用于模拟物体在运动中逐渐失去动力而自然停止的场景,如滚动的球体因摩擦力而减速静止。
  • AnticipateInterpolator:独具前瞻性,在动画正式启动之前,先巧妙地向反方向微微一动,如同运动员起跑前的下蹲蓄力,随后如离弦之箭加速前行,为动画增添了一丝俏皮与期待感,常用于交互元素的反馈动画,如按钮点击时的预收缩效果。
  • OvershootInterpolator:在动画即将抵达终点时,激情澎湃地超越目标值,而后心满意足地回归本位,恰似跳远运动员奋力一跃后略微超出起跳线,这种超越与回拉的过程为动画赋予了强烈的弹性和活力,常用于强调动画的结束效果,如元素的放大与回弹。
  • BounceInterpolator:临近目标时,数值如欢快的跳跳球般上下跳跃,反复多次,仿佛物体在富有弹性的表面上纵情蹦跶,为动画注入了活泼俏皮的元素,常用于模拟具有弹性碰撞效果的动画,如掉落的物体在地面上的多次反弹。
  • FastOutSlowInInterpolator:作为 Material Design 动画风格的代表插值器之一,它遵循快速启动、缓慢结束的原则,与人类视觉感知的特性高度契合,能够营造出自然流畅且富有韵律的动画效果,在现代 Android 应用的界面转场和元素动画中广泛应用,如页面切换时的淡入淡出与滑动效果。
  • PathInterpolator:提供了更为自由定制的动画路径,开发者可根据需求绘制任意形状的动画进度曲线,从而实现独一无二、别具一格的动画节奏,如自定义形状的路径移动动画或复杂的非线性数值变化动画。

具体效果参考下图
在这里插入图片描述

1:AccelerateDecelerateInterpolator 加速减速插补器(先慢后快再慢)
2:AccelerateInterpolator 加速插补器(先慢后快)
3:AnticipateInterpolator 向前插补器(先往回跑一点,再加速向前跑)
4:AnticipateOvershootInterpolator 向前向后插补器(先往回跑一点,再向后跑一点,再回到终点)
5:BounceInterpolator 反弹插补器(在动画结束的时候回弹几下,如果是竖直向下运动的话,就是玻璃球下掉弹几下的效果)
6:CycleInterpolator 循环插补器(按指定的路径以指定时间(或者是偏移量)的1/4、变速地执行一遍,再按指定的轨迹的相反反向走1/2的时间,再按指定的路径方向走完剩余的1/4的时间,最后回到原点。假如:默认是让a从原点往东跑100米。它会先往东跑100米,然后往西跑200米,再往东跑100米回到原点。可在代码中指定循环的次数)
7:DecelerateInterpolator 减速插补器(先快后慢)
8:LinearInterpolator 直线插补器(匀速)
9:OvershootInterpolator 超出插补器(向前跑直到越界一点后,再往回跑)
10:FastOutLinearInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 慢慢快
11:FastOutSlowInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 慢快慢
12:LinearOutSlowInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 快慢慢

参考文献:https://blog.csdn.net/pengkv/article/details/50488171

四、Java/Kotlin 代码实战演示

(一)补间动画实例

以下是一个运用 Java 代码创建补间动画的完整示例,以实现一个 ImageView 的旋转与缩放动画组合:

import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;

public class TweenAnimationExample {

    public static void startComplexTweenAnimation(ImageView imageView) {
        // 创建旋转动画对象
        RotateAnimation rotateAnimation = new RotateAnimation(
                0f,  // 起始角度
                360f, // 结束角度
                Animation.RELATIVE_TO_SELF, 0.5f,  // 旋转参考点 X 坐标(相对于自身中心)
                Animation.RELATIVE_TO_SELF, 0.5f); // 旋转参考点 Y 坐标(相对于自身中心)
        rotateAnimation.setDuration(2000);  // 动画时长为 2000 毫秒
        rotateAnimation.setRepeatCount(Animation.INFINITE);  // 设置无限循环

        // 创建缩放动画对象
        ScaleAnimation scaleAnimation = new ScaleAnimation(
                1.0f, 2.0f,  // X 方向从原始大小到放大两倍
                1.0f, 2.0f,  // Y 方向从原始大小到放大两倍
                Animation.RELATIVE_TO_SELF, 0.5f,  // 缩放参考点 X 坐标(相对于自身中心)
                Animation.RELATIVE_TO_SELF, 0.5f); // 缩放参考点 Y 坐标(相对于自身中心)
        scaleAnimation.setDuration(2000);  // 动画时长为 2000 毫秒
        scaleAnimation.setRepeatCount(Animation.INFINITE);  // 设置无限循环

        // 创建动画集合,将旋转和缩放动画组合在一起
        AnimationSet animationSet = new AnimationSet(true);
        animationSet.addAnimation(rotateAnimation);
        animationSet.addAnimation(scaleAnimation);

        // 将动画应用到ImageView上
        imageView.startAnimation(animationSet);
    }
}

在上述代码中,首先分别创建了 RotateAnimation 和 ScaleAnimation 对象,分别实现了 360 度的无限循环旋转以及从原始大小到两倍大小的无限循环缩放效果,然后将这两个动画添加到 AnimationSet 中,形成一个动画组合,最后将该动画组合应用到指定的 ImageView 上,使其同时进行旋转和缩放动画。

(二)属性动画实例

以下是一个使用 Kotlin 代码实现属性动画的示例,用于动态改变一个 View 的背景颜色:

import android.animation.ObjectAnimator
import android.graphics.Color
import android.view.View

fun startColorAnimation(view: View) {
    val animator = ObjectAnimator.ofArgb(
        view,  // 目标对象
        "backgroundColor",  // 属性名称
        Color.RED,  // 起始颜色
        Color.BLUE  // 结束颜色
    )
    animator.duration = 3000
    animator.start()
}

在这个示例中,借助 ObjectAnimator 的 ofArgb 方法,创建了一个针对 View 背景颜色的属性动画,从红色平滑过渡到蓝色,动画时长设定为 3000 毫秒,随后启动该动画,即可看到 View 的背景颜色逐渐变化的绚丽效果。

(三)转场动画实例

以下是一个更为详细的转场动画示例,展示了如何在 Fragment 之间实现带有共享元素的转场动画:

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.transition.ChangeBounds;
import androidx.transition.Transition;
import androidx.transition.TransitionInflater;

public class TransitionAnimationExample {

    public static void performFragmentTransition(FragmentManager fragmentManager,
                                                 Fragment fragmentStart,
                                                 Fragment fragmentEnd,
                                                 int containerViewId,
                                                 int sharedElementId) {
        // 加载共享元素过渡动画资源
        Transition transition = TransitionInflater.from(fragmentManager.getContext())
              .inflateTransition(android.R.transition.move);

        // 设置共享元素过渡动画
        Transition sharedElementTransition = new ChangeBounds();
        sharedElementTransition.setDuration(500);
        transition.addTarget(sharedElementId);
        transition.addTransition(sharedElementTransition);

        // 开启 Fragment 事务
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        // 添加共享元素过渡动画到事务中
        fragmentTransaction.addSharedElement(fragmentStart.getView().findViewById(sharedElementId),
                sharedElementId);
        fragmentTransaction.replace(containerViewId, fragmentEnd);
        fragmentTransaction.addToBackStack(null);

        // 设置过渡动画到事务中
        fragmentTransaction.setTransition(transition);

        // 提交事务,触发转场动画
        fragmentTransaction.commit();
    }
}

在上述示例中,首先通过 TransitionInflater 加载了一个预定义的共享元素过渡动画资源,然后创建了一个 ChangeBounds 过渡动画作为共享元素的特定动画效果,设定时长为 500 毫秒,并将其添加到总的过渡动画中,指定了共享元素的 ID。接着开启 Fragment 事务,添加共享元素过渡动画和替换 Fragment 的操作到事务中,并设置事务的过渡动画,最后提交事务,从而触发带有共享元素的 Fragment 转场动画,在转场过程中,共享元素将按照指定的动画效果进行平滑过渡。

五、Android 动画最佳实践与性能优化秘籍

(一)性能至上:UI 线程减负与硬件加速

动画的流畅性是优质用户体验的关键所在,而这在很大程度上依赖于性能的优化。由于 UI 线程肩负着绘制界面与响应用户操作的重任,复杂且耗时的动画操作极易导致 UI 线程阻塞,进而引发界面卡顿甚至无响应的尴尬局面。因此,在动画开发过程中,应极力避免在 UI 线程进行冗长的计算或复杂的布局调整。对于那些计算密集型或可能影响布局结构的动画任务,可考虑采用异步处理机制,比如利用 Handler 机制将耗时动画计算任务切换到工作线程去执行,待计算完成后再通过 Handler 将结果回传到 UI 线程进行界面更新和动画展示;或者使用 Android 提供的 AsyncTask(虽然已逐渐不推荐使用,但在一些简单场景下仍可行)、RxJava 等异步框架来处理相关逻辑,确保 UI 线程能保持流畅地响应用户交互操作。

另外,硬件加速也是提升动画性能的一大利器。Android 系统允许对整个应用或者特定的 View 开启硬件加速功能,通过利用 GPU 的图形处理能力来加速动画渲染过程。可以在 AndroidManifest.xml 文件中针对整个应用开启硬件加速,例如:

<application
    android:hardwareAccelerated="true"
   ... >
   ...
</application>

如果只想对特定的 View 启用硬件加速,在代码中可以这样操作(以一个 LinearLayout 为例):

LinearLayout linearLayout = findViewById(R.id.myLinearLayout);
linearLayout.setLayerType(View.LAYER_TYPE_HARDWARE, null);

不过需要注意的是,开启硬件加速并非毫无代价,它可能会增加内存消耗等问题,所以要根据实际情况合理选择开启的范围,并且在一些特定场景下(如存在兼容性问题或者某些绘制效果异常时),也可以选择关闭硬件加速,像这样:

linearLayout.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

(二)用户体验:适度与自然兼顾

动画的目的在于增强用户体验,而非给用户造成困扰,所以要确保动画流畅自然,避免出现突兀、闪烁或者过快过慢等影响视觉感受的情况。

一方面,动画的时长设置应合理,过短的动画可能让用户来不及察觉,起不到应有的引导和提示作用;而过长的动画则容易让用户产生等待的厌烦情绪。例如,一个简单的元素淡入淡出动画,时长通常设置在 300 - 800 毫秒之间比较合适,具体时长可根据动画的复杂程度以及整个应用的风格来综合确定。

另一方面,动画的运动轨迹和节奏也要符合现实世界的物理规律或者人们的视觉习惯,尽量模拟自然的运动状态。像前面提到的插值器的合理运用就能很好地控制动画节奏,如使用 AccelerateDecelerateInterpolator 让动画有先加速后减速的自然过渡,模拟物体的弹性运动,使用 BounceInterpolator 来呈现物体碰撞反弹的效果等,使动画效果更加逼真、舒适,让用户在操作应用时感觉更加顺畅、愉悦。

同时,也要注意不过度使用动画,避免界面上动画元素过多、过于繁杂,导致视觉疲劳。比如在一个页面中,不要同时设置多个大面积、高频率闪烁或者剧烈运动的动画效果,而是要有主次之分,重点突出需要引导用户关注的动画元素,营造简洁明了又富有活力的界面氛围。

(三)兼容性:全 API 级别适配

在开发 Android 应用时,需要考虑到应用可能会运行在不同版本的 Android 设备上,所以要确保动画能在所有支持的 API 级别上正常工作。

有些新特性或者动画 API 可能只在较高版本的 Android 系统中才支持,对于这类情况,需要做好向下兼容处理。例如,在使用一些较新的转场动画 API 时,如果应用需要兼容低版本系统,可以通过条件判断来使用不同的实现方式,在高版本中使用新的 API 来实现炫酷的转场效果,而在低版本中采用传统的、兼容性更好的动画手段来模拟类似的过渡效果,保证不同版本设备上的用户都能获得相对一致的体验。

还可以借助 Android 提供的支持库或者兼容库,这些库通常会对新功能进行向下兼容处理,开发者可以直接引入使用,减少自己处理兼容性问题的工作量。比如 androidx.transition 库中提供了很多转场动画相关的类,它在一定程度上保证了不同 API 级别设备上转场动画功能的可用性,开发者在项目中合理使用这些支持库,能更好地应对兼容性挑战,让动画在各种 Android 设备上都能稳定、流畅地展现。

通过遵循以上这些最佳实践原则,开发者能够打造出性能优异、用户体验良好且兼容性强的 Android 动画效果,为应用的交互界面增色不少,提升应用在市场中的竞争力和用户的满意度。

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

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

相关文章

Linux-ubuntu之主频和时钟配置

Linux-ubuntu之主频和时钟配置 一&#xff0c;主频二&#xff0c;其它时钟配置1.PLL2和PLL3的PFD0-3设置2.AHB_CLK_ROOT3.IPG 和 PERCLK时钟 三&#xff0c;总结 一&#xff0c;主频 24MHz 晶振为内核和其它外设提供时钟源&#xff0c;经电路后到PLL1变为996MHZ&#xff0c;再…

Autosar入门_汽车电子控制器

上一篇 | 返回主目录 汽车电子控制器 1 汽车电子控制器定义2 从功能角度来看构成2.1 车门控制器简单示例2.1.1 解锁过程分析2.1.2 无框车窗短降2.1.3 下电控制电耗2.2 控制器几大基本功能 3 从硬件构成角度看构成3.1 芯片类别说明3.2 芯片与功能联系 1 汽车电子控制器定义 汽…

变压器“变压”和“变流”说明

变压器可以改变交流电压的大小&#xff0c;也可以改变交流电流的大小。 改变交流电压 变压器既可以升高交流电压&#xff0c;也能降低交流电压。在忽略电能损耗的情况下&#xff0c;变 压器电压U、二次电压U2与烧组匝数N、二次烧组匝数的关系为&#xff1a; n称为匝数比或电…

初学stm32 --- 时钟配置

目录 stm32时钟系统 时钟源 &#xff08;1&#xff09; 2 个外部时钟源&#xff1a; &#xff08;2&#xff09;2 个内部时钟源&#xff1a; 锁相环 PLL PLLXTPRE&#xff1a; HSE 分频器作为 PLL 输入 (HSE divider for PLL entry) PLLSRC&#xff1a; PLL 输入时钟源 (PL…

[机器学习]XGBoost(3)——确定树的结构

XGBoost的目标函数详见[机器学习]XGBoost&#xff08;2&#xff09;——目标函数&#xff08;公式详解&#xff09; 确定树的结构 之前在关于目标函数的计算中&#xff0c;均假设树的结构是确定的&#xff0c;但实际上&#xff0c;当划分条件不同时&#xff0c;叶子节点包含的…

常用命名总结

命名在编程中是非常重要的&#xff0c;它直接影响到代码的可读性、可维护性和开发效率。一个好的命名能够让代码更加直观、易于理解和修改&#xff0c;反之&#xff0c;不恰当的命名可能导致混乱、错误和难以调试的问题。以下是一些关于命名的最佳实践和原则&#xff1a; 1. 简…

AutoMQ 流表一体新特性 Table Topic 发布: 无缝集成 AWS S3 Table 和 Iceberg

超越共享存储&#xff1a;使用 Apache Iceberg 中的 AutoMQ Table Topic 实现流处理与分析的统一 自 2023 年底官宣以来&#xff0c;AutoMQ 成功地将 Apache Kafka 从“Shared Nothing architecture”转变为“Shared Storage architecture”&#xff0c;这为京东、知乎、小红书…

maven使用Dependency-Check来扫描安全漏洞

在现代软件开发中&#xff0c;使用开源库和第三方依赖项已成为常态。然而&#xff0c;这些依赖项可能包含已知的安全漏洞&#xff0c;给应用程序带来潜在的风险。为了解决这个问题&#xff0c;OWASP Dependency-Check 应运而生。本文将介绍 OWASP Dependency-Check 的功能、安装…

#渗透测试#红队全栈 powshell基础使用

声明&#xff01; 学习视频来自B站up主 泷羽sec&#xff0c;任何违法事件与本人以及泷羽sec团队无关&#xff0c;切勿触碰法律底线&#xff0c;否则后果自负&#xff01;&#xff01;&#xff01;&#xff01; 目录标题 认识powsehll打开方式 使用方式美化自己的powershell简单…

Qt:QMetaObject::connectSlotsByName实现信号槽自动关联

简介 在Qt中&#xff0c;QMetaObject::connectSlotsByName 是一个便利的方法&#xff0c;它可以根据对象的对象名&#xff08;objectName&#xff09;自动将信号和槽连接起来。但是&#xff0c;要使用这个方法&#xff0c;必须确保&#xff1a; 1 控件&#xff08;如按钮&…

《算法ZUC》题目

判断题 ZUC算法LFSR部分产生的二元序列具有很低的线性复杂度。 A.正确 B.错误 正确答案A 单项选择题 ZUC算法驱动部分LFSR的抽头位置不包括&#xff08; &#xff09;。 A.s15 B.s10 C.s7 D.s0 正确答案C 单项选择题 ZUC算法比特重组BR层主要使用了软件实现友好的…

maven项目中对不同目录下的同包同名类的引用情况整理

说明 maven项目&#xff0c;允许在不同目录中出现相同包名和相同类名&#xff0c;不会出现冲突&#xff0c;包括&#xff1a; java目录test目录依赖中目录 这里就用Hutool.class类中的一个常量做测试&#xff0c;如图 好奇同包同名类同时存在时&#xff0c;会加载哪个类 Syst…

【UE5 C++课程系列笔记】10——动态单播/多播的基本使用

目录 概念 申明动态委托 一、DECLARE_DYNAMIC_DELEGATE 二、DECLARE_DYNAMIC_MULTICAST_DELEGATE 绑定动态委托 一、BindDynamic 二、AddDynamic 三、RemoveDynamic 执行动态委托 ​一、Execute 二、ExecuteIfBound 三、IsBound 四、Broadcast 动态单播使用示…

Redis篇-19--运维篇1-主从复制(主从复制,读写分离,配置实现,实战案例)

1、概述 Redis的主从复制&#xff08;Master-Slave Replication&#xff09;是一种数据冗余机制&#xff0c;它允许将一台Redis服务器的数据复制到其他Redis服务器。在主从复制中&#xff0c;有一台主服务器&#xff08;Master&#xff09;和一个或多个从服务器&#xff08;Sl…

【ORACLE】一个允许关键字作为别名所引起的语法歧义场景

前言 最近在看SQL语法解析器&#xff0c;发现了antlr4提供的PlSql语法树存在一个BUG&#xff0c;然后我顺着这个BUG&#xff0c;构造了一条SQL&#xff0c;在ORACLE执行&#xff0c;如下 然后神奇的事情出现了&#xff0c;这个查询竟然没有返回行&#xff01;t1表左关联t2&…

【前端】Jquery拍照,通过PHP将base64编码数据转换成PNG格式,并保存图像到本地

目录 一、需求 二、开发语言 三、效果 四、业务逻辑&#xff1a; 五、web端调用摄像头 六、示例代码 1、前端 2、后端 一、需求 web端使用jquery调用摄像头拍照&#xff0c;并使用PHP把base64编码转换成png格式图片&#xff0c;下载到本地。 由于js不能指定图片存储的…

本地摄像头视频流在html中打开

1.准备ffmpeg 和(rtsp-simple-server srs搭建流媒体服务器)视频服务器. 2.解压视频流服务器修改配置文件mediamtx.yml ,hlsAlwaysRemux: yes 3.双击运行服务器。 4&#xff0c;安装ffmpeg ,添加到环境变量。 5.查询本机设备列表 ffmpeg -list_devices true -f dshow -i d…

机器情绪及抑郁症识别算法(六)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

34. Three.js案例-创建球体与模糊阴影

34. Three.js案例-创建球体与模糊阴影 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它负责将场景中的对象绘制到画布上。 构造器 new THREE.WebGLRenderer(parameters)参数类型描述parametersObject可选参数对象&#xff0c;包…

服务器数据恢复—RAIDZ离线硬盘数超过热备盘数导致阵列崩溃的数据恢复案例

服务器存储数据恢复环境&#xff1a; ZFS Storage 7320存储阵列中有32块硬盘。32块硬盘分为4组&#xff0c;每组8块硬盘&#xff0c;共组建了3组RAIDZ&#xff0c;每组raid都配置了热备盘。 服务器存储故障&#xff1a; 服务器存储运行过程中突然崩溃&#xff0c;排除人为误操…