一、属性动画简介

Android 中动画有很多种,属性动画就是其中的一种。所谓的属性动画,就是在指定的时间内,通过改变对象的属性达到变化效果的动画。在 Android 中,属性动画系统是一个强健的框架,几乎可以为任何内容添加动画效果。实现属性动画也是通过 Android 的属性动画系统实现,开发者只需要定义动画的一些属性即可完成,这些属性如下:

  • 时长(duration):指定动画的时长。默认时长为 300 毫秒。
  • 时间插值(interpolator):指定如何根据当前动画的已播放时长来计算属性的值。
  • 重复计数和行为(repeatCount、repeatMode):指定是否在时长结束后重复播放动画以及重复播放动画多少次、循环行为(reverse、restart)。
  • Animator 集:将动画分成由多个动画集组成,这些动画集可以一起播放、按顺序播放或者在指定的延迟时间后播放。
  • 帧刷新延迟:指定动画帧的刷新频率。默认设置为每 10 毫秒刷新一次,但应用刷新帧的速度最终取决于整个系统的繁忙程度以及系统为底层计时器提供服务的速度。

二、属性动画的工作原理

2.1 属性动画的计算

属性动画是通过在指定时间内改变对象的属性达到变化的动画,按照一定的帧速,计算出每帧属性的变化量,实现各种动画效果(如:匀速动画、加速动画效果等)。

    上图描绘了属性动画中,主类之间是如何相互协作的。

  • ValueAnimator 对象跟踪动画的时间,例如动画的已运行时长以及添加了动画效果的属性的当前值。ValueAnimator 包含 TimeInterpolatorTypeEvaluator

    • TimeInterpolator:插值器,用于定义动画插值,即动画完成比例与动画时间比例之间的关系(动画完成比例跟动画时间比例不一定一致)。
    • TypeEvaluator:类型评估程序,用于定义在动画中如何计算添加了动画效果的属性的值,即属性值跟时间之间的关系(随着时间如何变化)。

要开始动画,首先要创建一个 ValueAnimator 对象,并为需要添加动画效果的属性设置起始值和结束值,并设置动画的时长。然后调用 start() 接口,动画就会播放。

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

视图动画系统仅提供为 View对象添加动画效果的功能,因此,如果您想为非 View对象添加动画效果,则必须实现自己的代码才能做到。视图动画系统也存在一些限制,它仅能为 View 对象的某些方面添加动画效果。例如:视图动画系统可以为视图的位置变化、形状变化添加动画,但是无法为背景颜色变化添加动画。

视图动画系统的另一个缺点就是它只会修改视图绘制位置,而不会修改实际的视图本身,换句话说,视图动画只是实现一种视图的动画效果,视图本身还是停留在原来的位置。例如:为 Button 对象添加视图移动的动画,在按钮移动动画播放过程中,按钮本身的点击事件并不会随着动画移动,如果要实现点击事件随动画变化,就需要自己另外实现了。

有了属性动画系统,就可以完全摆脱这些束缚,还可以为任何对象(视图和非视图)的任何属性添加动画效果,并且实际修改的是对象本身。属性动画系统在执行动画方面也更为强健。概括地讲,通过属性动画系统可以为要添加动画效果的属性(例如颜色、位置或大小)分配 Animator,还可以定义动画的各个方面,例如多个 Animator 的插值和同步。

不过,视图动画也是有它的有点,视图动画系统的设置需要的时间较短,需要编写的代码也较少。在开发过程中,如果视图动画可以完成需要执行的所有操作,或者现有代码已按照您需要的方式运行,则无需使用属性动画系统。在某些用例中,也可以针对不同的情况同时使用这两种动画系统。

2.3 常用 API 概览

前面讲到了ValueAnimatorTimeInterpolatorTypeEvaluator几个类,可能大家有点蒙圈,其实在实际使用过程中,有现成的插值器是可以使用的。在 android.animation 包下面可以找到属性动画的大多数 API(类),另外,视图动画系统在 android.view.animation 包下面定义了许多插值器,这些插值器是可以直接在属性动画系统中使用的。

2.3.1 Animator

属性动画由抽象类 Animator 提供了创建动画的基本结构,但是必须通过扩展该类才能实现属性值动画,系统 API 已经包含了常用的扩展类供开发者使用。

  • ValueAnimatorAnimator 抽象类的直接子类,是属性动画的主计时引擎,它也可计算要添加动画效果的属性的值。它具有计算动画值所需的所有核心功能,同时包含每个动画的计时详情、有关动画是否重复播放的信息、用于接收更新事件的监听器以及设置待评估自定义类型的功能。为属性添加动画效果分为两个步骤:计算添加动画效果之后的值,以及对要添加动画效果的对象和属性设置这些值。ValueAnimator 不会执行第二个步骤,因此,您必须监听由 ValueAnimator 计算的值的更新情况,并使用您自己的逻辑修改要添加动画效果的对象。

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

  • AnimatorSet:这个类提供一种将动画分组的机制,也就是将多个动画(或者动画跟动画组)组合在一起,以使它们彼此相对运行。通过这个类可以将动画设置为一起播放、按顺序播放或者在指定的延迟时间后播放。

2.3.2 插值器

前面讲到插值器用于定义动画完成比例与动画时间比例之间的关系。系统定义了一些插值器,开发者可以直接使用,当然,在必要时可以实现自己的插值器,实现自己的插值器需要继承 TimeInterpolator 类。系统常用的插值器有以下几个:

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

2.3.3 评估程序

前面提到评估程序是用于定义在动画中如何计算添加了动画效果的属性的值,即属性值跟时间之间的关系的,根据动画时间,计算出属性当前的值。系统定义的评估程序有以下几种:

  • IntEvaluator:这是用于计算 int 类型属性的值的默认评估程序。
  • FloatEvaluator:这是用于计算 float 类型属性的值的默认评估程序。
  • ArgbEvaluator:这是用于计算颜色属性的值(用十六进制值表示)的默认评估程序。
  • TypeEvaluator:此接口用于创建自定义的评估程序。如果要添加动画效果的对象属性不是 intfloat 或颜色,就可以自定义的评估程序,自定义评估程序必须实现 TypeEvaluator 接口,才能计算出对象属性在添加动画效果之后的值。

三、使用入门

3.1 使用 ValueAnimator 添加动画效果

借助 ValueAnimator 类,可以为动画播放期间某些类型的值添加动画效果,只需指定一组要添加动画效果的 intfloat 或颜色值即可。

可以通过调用 ValueAnimator 的任一工厂方法来获取 ValueAnimator 实例对象:ofInt()ofFloat()ofObject()。然后设置相应的动画参数(时长、重复模式、重复次数等等),最后调用 start() 方法开始动画。示例:

ValueAnimator.ofFloat(1.0f, 2.0f).apply {duration = 1000 // 动画时长repeatMode = ValueAnimator.REVERSE // 重复模式(重新开始)repeatCount = ValueAnimator.INFINITE // 重复次数(无限循环)start()
}

注意事项:前面提到,ValueAnimator 为属性添加动画效果分为两个步骤,计算属性值和设置对象的属性值。ValueAnimator 计算出属性值,但是不会执行第二步(设置对象属性值) ,因此,必须添加 AnimatorUpdateListener 监听由 ValueAnimator 计算的值的更新情况,并将新值设置到对象的属性中。

通过添加 AnimatorUpdateListener 监听计算值的更新,在 onAnimationUpdate()ValueAnimator 计算的值,设置到对象的相应属性中,让动画展现出来。

ValueAnimator.ofFloat(1.0f, 2.0f).apply {duration = 1000 // 动画时长repeatMode = ValueAnimator.REVERSE // 重复模式(重新开始)repeatCount = ValueAnimator.INFINITE // 重复次数(无限循环)addUpdateListener { // 添加 AnimatorUpdateListener 监听// ValueAnimator 无法自动将更新的属性值设置到对象的属性中,只能在监听中实现对象属性值的设置。// 监听到计算值的更新,并设置到对象属性中val value = it.animatedValue as FloatimageView.scaleX = valueimageView.scaleY = value}start()
}
  • 实现效果

温馨提示:ValueAnimator 的工厂方法(ofInt()ofFloat()ofObject())是支持传入多个值的,至少有两个值才会有动画效果。ValueAnimator 有自己默认的插值器,默认的插值器是 AccelerateDecelerateInterpolator

3.2 使用 ObjectAnimator 添加动画效果

在前面已经提到 ObjectAnimatorValueAnimator 的子类,它继承了父类的动画引擎和值计算等,灵活性虽然不及 ValueAnimator ,但是 ObjectAnimator 支持通过属性名称为目标对象属性添加动画效果,这可以极大地简化为对象添加动画效果的过程,而且动画属性会自动更新,无需再实现 ValueAnimator.AnimatorUpdateListener

实例化 ObjectAnimatorValueAnimator 的过程类似,但实例化 ObjectAnimator 对象时可以传入该对象需要添加动画的属性的名称(以字符串形式),以及实现动画效果的属性值(列表)。

  • 示例代码
ObjectAnimator.ofFloat(imageView, "scaleY", 1.0f, 2.0f).apply {repeatMode = ValueAnimator.REVERSErepeatCount = ValueAnimator.INFINITEduration = 1000start()
}

第一个参数是目标对象,第二个参数是属性名称,第三个参数是个数组,是属性值列表。

  • 实现效果

        要使 ObjectAnimator 正确更新属性实现动画效果,必须执行以下操作:

  • 传入的属性名称(即要添加动画效果的对象属性)必须具有 set<PropertyName>() 形式的 setter 函数(采用驼峰式大小写形式)。由于 ObjectAnimator 会在动画过程中自动更新属性,所以必须能够使用此 setter 方法访问该属性。例如,上面提到的 scaleX,则需要存在 setScaleX() 方法,并且有权限调用。如果此 setter 方法不存在,有三个选择可以处理:

    • 如果有权限修改类,可将 setter 方法添加到类中。
    • 使用有权限更改的封装容器类,并在该封装容器使用有效的 setter 方法接收值并将其转发给原始对象。
    • 改用 ValueAnimator
  • 如果在 ObjectAnimator 的工厂方法中,仅指定一个值,则系统会假定它是动画的结束值。因此,要添加动画效果的对象属性必须具有用于获取属性起始值的 getter 函数。getter 函数必须采用 get<PropertyName>() 形式。例如,上面提到的 scaleX 必须要有 getScaleX() 方法。

  • 要添加动画效果的属性的 getter(如果需要)和 setter 方法的操作对象必须与 ObjectAnimator 指定的起始值和结束值的类型相同。

  • 根据要添加动画效果的属性或对象,可能需要对视图调用 invalidate() 方法,以强制屏幕使用添加动画效果之后的值重新绘制自身。可以在 onAnimationUpdate() 回调中执行此操作(视图的所有属性 setter(如 setAlpha() 和 setScaleX())都会使视图失效,因此,在使用新值调用这些方法时,您无需使视图失效)。

3.3 使用 AnimatorSet 编排多个动画

前面介绍的属性动画是单个动画(当然,你可以使用 ValueAnimator 同时为多个属性设置动画效果,但这个局限于同时执行),通过 AnimatorSet 可以将多个动画编排在一起(也可以嵌套 AnimatorSet),并可控制不同的动画之间的播放关系(之前播放、一起播放、之后播放等)。AnimatorSet 构建完成之后,调用 start() 启动动画。

  • 示例
// 定义X方向缩放动画
val scaleXAnim = ObjectAnimator.ofFloat(imageView, "scaleY", 1.0f, 2.0f).apply {duration = 1000
}// 定义Y方向缩放动画
val scaleYAnim = ObjectAnimator.ofFloat(imageView, "scaleX", 1.0f, 2.0f).apply {duration = 1000
}// 定义缩放AnimatorSet
val scaleAnimSet = AnimatorSet().apply {// 同时播放X缩放动画和Y缩放动画play(scaleXAnim).with(scaleYAnim)}// 定义透明度动画
val alphaAnim = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.0f).apply {duration = 1000
}// 定义AnimatorSet
AnimatorSet().apply {// 先播放缩放AnimatorSet,接着播放透明度动画play(scaleAnimSet).before(alphaAnim)// 启动AnimatorSetstart()
}
  • 效果

注意事项:
1. 组合成 AnimatorSetAnimator 在定义是不要调用 start() 方法;
2. AnimatorSet 开始播放动画需要调用 start() 方法;
3. AnimatorSet

3.4 动画监听

属性动画监听有两个,分别是 Animator.AnimatorListenerValueAnimator.AnimatorUpdateListener,都是用来监听动画播放期间的重要事件。

  • Animator.AnimatorListener:监听动画的各个状态,回调方法有:

    • onAnimationStart() - 在动画开始播放时回调。
    • onAnimationEnd() - 在动画结束播放时回调,无论何种方式结束动画都会调用。
    • onAnimationRepeat() - 在动画重复播放时回调。
    • onAnimationCancel() - 在动画取消播放时回调,取消的动画也会调用 onAnimationEnd()
  • ValueAnimator.AnimatorUpdateListener:监听动画的更新事件,回调方法有:

    • onAnimationUpdate() - 在动画的每一帧回调。使用此监听可以在动画播放过程中实时获取生成的计算值,通过回调方法参数 ValueAnimator 对象的 getAnimatedValue() 方法可以获取当前计算值,通过此计算值可以更新动画效果。如果使用 ValueAnimator 实现属性动画,则必须通过此监听来更新动画(ValueAnimator 不会自动更新动画)。在此回调方法中更改视图的动画效果,可能需要对视图调用 invalidate() 方法更新视图。如果调用视图的方法进行更新动画,并且改方法包含了 invalidate() ,则无需再调用 invalidate() ,例如:视图的 setScaleX()setAlpha() 等方法。

如果不需要实现 Animator.AnimatorListener 接口的所有方法,则可以扩展 AnimatorListenerAdapter类,AnimatorListenerAdapter类提供了方法的空实现。

3.5 在 XML 资源中定义属性动画

Android 提供了强大的 XML 资源定义,也包括了属性动画。属性动画 XML 资源放在 res/animator 目录下。

3.5.1 XML资源定义 ValueAnimator

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:repeatMode="reverse"android:repeatCount="infinite"android:valueType="floatType"android:valueFrom="1.0"android:valueTo="2.0"></animator>

在代码中使用 AnimatorInflater.loadAnimator() 方法加载动画,并调用 start() 方法播放动画。

(AnimatorInflater.loadAnimator(this@LayoutAnimActivity, R.animator.animator_scale) as ValueAnimator).apply {addUpdateListener {// ValueAnimator 无法自动将更新的属性值设置到对象的属性中,只能在监听中实现对象属性值的设置。val value = it.animatedValue as FloatimageView.scaleX = valueimageView.scaleY = value}start()
}

说明:因为 ValueAnimator 不会自动更新视图属性,所以,在 XML 定义 ValueAnimator 时,在代码中加载动画时,仍需要添加 AnimatorUpdateListner 并在回调方法中更新视图属性,实现动画效果。

在代码中定义 ValueAnimator 时,可以指定多个值,但在 XML 中只能定义 valueFromvalueTo 两个值。不过在 API 23 开始,XML 定义动画增加了关键帧的概念,而且每个关键帧(使用 propertyValuesHolderkeyframe 标签定义)还可以定义不同的插值器。

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:repeatMode="reverse"android:repeatCount="infinite"><propertyValuesHolder><keyframe android:valueType="floatType" android:fraction="0" android:value="1.0" /><keyframe android:valueType="floatType" android:fraction="0.5" android:value="1.2" /><keyframe android:valueType="floatType" android:fraction="1" android:value="2.0" /></propertyValuesHolder></animator>

添加关键帧用 propertyValuesHolder 标签封装,每一个关键帧用 keyframe 标签定义。android:fraction 是关键帧在动画过程中的位置(占比分数)。

3.5.2 XML 资源定义 ObjectAnimator

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:repeatMode="reverse"android:repeatCount="infinite"android:valueType="floatType"android:valueFrom="1.0"android:valueTo="0.0"android:propertyName="alpha">
</objectAnimator>

在代码中使用 AnimatorInflater.loadAnimator() 方法加载动画,设置目标,并调用 start() 方法播放动画。

(AnimatorInflater.loadAnimator(this@LayoutAnimActivity, R.animator.animator_alpha) as ObjectAnimator).apply {target = imageView // ObjectAnimator 需要设置目标start()
}

在 API 23 开始,同样可以使用关键帧(使用 propertyValuesHolderkeyframe 标签定义),用来定义更加复杂的动画,而且每个关键帧还可以定义不同的插值器。

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:repeatMode="reverse"android:repeatCount="infinite"><propertyValuesHolder android:propertyName="alpha" android:valueType="floatType"><keyframe android:valueType="floatType" android:fraction="0.0" android:value="1.0" /><keyframe android:valueType="floatType" android:fraction="0.5" android:value="0.2" /><keyframe android:valueType="floatType" android:fraction="1.0" android:value="0.0" /></propertyValuesHolder>
</objectAnimator>

注意事项:
1. 在 XML 中定义 ObjectAnimator 的时候,必须指定添加动画的属性,在代码中加载动画之后,也需要设置目标,并调用 start() 才会启动动画;
2. 如果使用了 propertyValuesHolder,必须在 propertyValuesHolder 标签内指定添加动画的属性名称;
3. 通过 propertyValuesHolder 可以实现同时为多个属性添加动画(类似 AnimatorSet 的效果),但是每个属性需要定义一个 propertyValuesHolder 标签(只有在 API 23 开始才支持)。

ObjectAnimator 使用 propertyValuesHolder 可以实现同时为多个属性添加动画效果

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:duration="1000"android:repeatMode="reverse"android:repeatCount="infinite"><propertyValuesHolder android:propertyName="alpha" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="0.0" /><propertyValuesHolder android:propertyName="scaleX" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="2.0" /><propertyValuesHolder android:propertyName="scaleY" android:valueType="floatType" android:valueFrom="1.0" android:valueTo="2.0" />
</objectAnimator>

3.5.3 XML 资源定义 AnimatorSet

ObjectAnimator 使用 propertyValuesHolder 同时为多个属性添加动画效果,仅API 23开始,低于使用 AnimatorSet 实现,一下示例跟上面有同样效果

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"android:ordering="together"><set><objectAnimatorandroid:duration="500"android:propertyName="scaleX"android:valueTo="1.5"android:valueType="floatType"android:repeatCount="infinite"android:repeatMode="reverse"/><objectAnimatorandroid:duration="500"android:propertyName="scaleY"android:valueTo="1.5"android:valueType="floatType"android:repeatCount="infinite"android:repeatMode="reverse" /></set><objectAnimator android:propertyName="alpha"android:duration="500"android:valueFrom="1.0"android:valueTo="0.5"android:valueType="floatType"android:repeatCount="infinite"android:repeatMode="reverse" />
</set>

四、编后语

Android 的属性动画非常强大,应用适当的话可以节省很多开发时间,本篇文章先介绍入门基础,后续会发表一些关于属性动画的使用技巧。


下一篇:Android 属性动画(二)为视图状态更改添加动画效果

Android 属性动画(一)新手入门相关推荐

  1. android动画封装,Android属性动画封装,快速构建动画

    Android实现动画效果的方式主要有帧动画.补间动画.属性动画.关于安桌动画的基础知识可以查看这篇文章Android属性动画完全解析 这里我要讲的是如何快速构建出一个动画效果,如下图: 如果我们用属 ...

  2. Android属性动画 ObjectAnimator

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/118709616 本文出自[赵彦军的博客] 文章目录 ObjectAnimator ...

  3. (转)Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法

    版权声明:本文出自郭霖的博客,转载必须注明出处. 目录(?)[-] ValueAnimator的高级用法 ObjectAnimator的高级用法 转载请注明出处:http://blog.csdn.ne ...

  4. android 属性动画实例,Android属性动画完全解析 中 ,ValueAnimator和ObjectAnimator的高级用法...

    大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法,当然也是最常用的一些用法,这些用法足以覆盖我们平时大多情况下的动画需求了.但是,正如上篇文章当中所说到的,属性动画对补间动画进行了 ...

  5. Android 系统(196)---Android 属性动画

    Android 属性动画 属性动画 总结&攻略 前言 动画的使用 是 Android 开发中常用的知识 本文将详细介绍 Android 动画中 属性动画的原理 & 使用 动画类型 关于 ...

  6. Android 属性动画Property Animation(中)

    Android 属性动画Property Animation(上)介绍了属性动画的概念以及相关的类和接口,本篇来看下具体肿么使用. ValueAnimator ValueAnimator指定整形.浮点 ...

  7. Android 属性动画使用(二)

    首先扯点别的:晚上稍微跑了一会步,然后逛了超市,晚饭喝的南瓜粥,吃了一碗面条,今天不是太饿,现在正一边吃着葡萄一边学习,也是没谁了. 比如说,我们想要实现从0过渡到100,使用ValueAnimato ...

  8. android+属性动画+高度,android 自定义view+属性动画实现充电进度条

    近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和 ...

  9. Android 属性动画 详解

    Android 属性动画 详解 Android动画类型: View Animation(即所谓的Tween Animation补间动画):View Animation相当简单,不过只能支持简单的缩放. ...

最新文章

  1. c# unity PlayerPrefs 游戏存档,直白点就是讲游戏数据本地保存下来
  2. Linux命令基础--uname
  3. 手把手教 | 使用Bert预训练模型文本分类(内附源码)
  4. Tensorflow中实现leakyRelu
  5. 使用ADO.NET操作数据库
  6. 每日一博 - CAS(Compare-And-Swap)原理剖析
  7. 保护可执行程序的一种方法
  8. Spark交互式分析平台Apache Zeppelin的安装
  9. vbox 中ubuntu20.04和宿主机共享文件_如何在家搭建一套自己的实验平台(10)iSCSI 共享存储...
  10. 行测(爆发篇)之语句表达,像说话一样自然
  11. mongodb windows的安装方法和添加到任务管理器中、检测是否成功、增删改查命令...
  12. ELK下logstash通过redis收集日志
  13. python有什么用-python是什么意思?python有什么用?
  14. jar k8s 自己的 部署_怎样部署K8S服务器
  15. java 生成拼音_JAVA生成拼音码
  16. 【目标检测】YOLOv1代码实现之TensorFlow
  17. chattr -i authorized_keys 无效
  18. 医院影像服务器系统,锐潮医学影像管理系统(PACS)
  19. Neo4j-Cypher
  20. Flink源码解析 | 从Example出发:理解Flink启动流程

热门文章

  1. DELL Inspiron 7391 2-in-1 jedi 15_cml_n17s-g2_2gb 18806-1笔记本电路图纸
  2. 真正的头号玩家——游戏AI
  3. 地震信号去噪学习(自用)
  4. 苹果刷机未知错误75_刷机ROOT后遇到Magisk提示需要修复允许环境怎么办?
  5. 一步一步教你反向传播,求梯度(A Step by Step Backpropagation Example)
  6. GTC 2019,英伟达和它叫不醒的To B梦
  7. 基于若依开发物品管理系统(springboot+vue)
  8. iphone11如何强制关机 苹果11手机一键强制重启方法教程
  9. SpringBoot+Mysql实现在线旅游订票系统
  10. 斐讯db2_斐讯P1刷armbian变身linux小型服务器