关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。
目录
一、导读
我们继续总结学习基础知识,温故知新。
本文我们就来讲讲安卓动画相关的知识。
二、概览
在Android中,动画我们大致分为两大类,
- 1、视图动画,即帧动画和补间动画
- 补间动画:通过使用 Animation 对单张图片执行一系列转换来创建动画,这是一种在 XML 中定义的动画(也可以代码配置),用于对图形执行旋转、淡出、移动和拉伸等转换。
- 帧动画:通过使用 AnimationDrawable 按顺序显示一系列图片来创建动画,就像放电影一样,一帧一帧的。
- 2、属性动画:通过使用 Animator 在设定的时段内修改对象的属性值来创建动画。
下面我们分别来讲这几种动画实现。
三、动画实现
3.1 帧动画
在 XML 中定义的按顺序显示一系列图片的动画(如电影)。我们在实际开发中可以用两种方式来做。
资源文件中实现帧动画
帧动画编译后的资源数据类型为 AnimationDrawable ,动画的开始是AnimationDrawable控制的。
1、 新建动画文件bg_animation.xml,文件位置:
res/drawable/filename.xml
文件名用作资源 ID。
语法如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] > 如果您想要执行一次动画,则为 "true";如果要循环播放动画,则为 "false"
<item
android:drawable="@[package:]drawable/drawable_resource_name" 可绘制资源
android:duration="integer" /> 显示此帧的持续时间,以毫秒为单位
</animation-list>
2、使用
// 要播放动画的组件设置resource
aivingImg.setImageResource(R.drawable.bg_animation);
// 通过组件找到对应的 AnimationDrawable ,资源文件编译后,就是这个玩意,所以要用到
AnimationDrawable animationDrawable = (AnimationDrawable) aivingImg.getDrawable();
// 开始动画
animationDrawable.start();
代码中实现帧动画
我们知道帧动画编译后的资源数据类型为 AnimationDrawable,所以可以直接操作这个类来播放动画。
AnimationDrawable常用方法
addFrame:添加一幅图片帧,并指定该帧的持续时间(单位毫秒)。
setOneShot:设置是否只播放一次。为true表示只播放一次,为false表示循环播放。
start:开始播放。注意,设置宿主视图后才能进行播放。
stop:停止播放。
isRunning:判断是否正在播放。
上代码
调用ImageView对象的setImageDrawable方法将动画图形加载到图像视图中
AnimationDrawable ad_frame = new AnimationDrawable();
ad_frame.addFrame(getResources().getDrawable(R.mipmap.flow_p1),50);
ad_frame.addFrame(getResources().getDrawable(R.mipmap.flow_p2),50);
ad_frame.setOneShot(false);
iv_pic.setImageDrawable(ad_frame);
ad_frame.start();
3.2 补间动画
补间动画是在 XML 中定义的动画,一种二维空间动画,补间动画根据动画的起点、终点、大小、旋转情况和其他常见方面来计算动画,
动画的方式无非就几种方式,旋转、淡出(透明度)、移动和拉伸等,该动画是作用在整个view上的,包含背景图。
- alpha:渐变透明度动画效果。
- scale:渐变尺寸伸缩动画效果。
- translate:画面变换位置移动动画效果。
- rotate:画面转移旋转动画效果。
- set:定义动画集。
动画编译后的资源数据类型为 Animation ,动画的开始是Animation控制的,另外还有 AnimationSet 承载属性。
3.2.1 基本语法
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 容纳其他动画元素 或其他 <set> 元素的容器。代表 AnimationSet
android:duration="5000" 动画时间,单位毫秒
android:startOffset="1000" 动画延迟执行时间
android:fillBefore="true" 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter="false" 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled="true" 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode="restart" 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount="3" 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator="@[package:]anim/interpolator_resource" 插值器资源
android:shareInterpolator=["true" | "false"] > 如果要在所有子元素中共用同一插值器,则为 "true"
<alpha 淡入或淡出动画(透明度)。代表 AlphaAnimation。
android:fromAlpha="float" 浮点数。起始不透明度偏移,0.0 表示透明,1.0 表示不透明。
android:toAlpha="float" /> 浮点数。结束不透明度偏移,0.0 表示透明,1.0 表示不透明。
<scale 拉伸动画。代表 ScaleAnimation。
android:fromXScale="float" 起始 X 尺寸偏移,其中 1.0 表示不变
android:toXScale="float" 结束 X 尺寸偏移,其中 1.0 表示不变。
android:fromYScale="float" 起始 Y 尺寸偏移,其中 1.0 表示不变
android:toYScale="float" 结束 Y 尺寸偏移,其中 1.0 表示不变
android:pivotX="float" 在对象缩放时要保持不变的 X 坐标,缩放起始点X轴坐标,可以是数值、百分数、百分数p三种样式,如50、50%、50%p
android:pivotY="float" /> 在对象缩放时要保持不变的 Y 坐标
<translate 竖直和/或水平 移动。代表 TranslateAnimation
android:fromXDelta="float" 浮点数或百分比。起始 X 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素宽度的百分比(例如 "5%");或相对于父项宽度的百分比(例如 "5%p")。
android:toXDelta="float" 浮点数或百分比。结束 X 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素宽度的百分比(例如 "5%");或相对于父项宽度的百分比(例如 "5%p")。
android:fromYDelta="float" 浮点数或百分比。起始 Y 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素高度的百分比(例如 "5%");或相对于父项高度的百分比(例如 "5%p")。
android:toYDelta="float" /> 浮点数或百分比。结束 Y 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素高度的百分比(例如 "5%");或相对于父项高度的百分比(例如 "5%p")。
<rotate 旋转动画。代表 RotateAnimation。
android:fromDegrees="float" 浮点数。起始角度位置,以度为单位。(0度指X轴正方向所在方向)
android:toDegrees="float" 浮点数。结束角度位置,以度为单位。
android:pivotX="float" 浮点数或百分比。旋转中心的 X 坐标。表示方式:相对于对象左边缘的像素数(例如 "5");相对于对象左边缘的百分比(例如 "5%");或相对于父级容器左边缘的百分比(例如 "5%p")。
android:pivotY="float" /> 浮点数或百分比。旋转中心的 Y 坐标。表示方式:相对于对象上边缘的像素数(例如 "5");相对于对象上边缘的百分比(例如 "5%");或相对于父级容器上边缘的百分比(例如 "5%p")。
<set>
...
</set>
</set>
- android:pivotX:。缩放起始点X轴坐标,可以是数值、百分数、百分数p三种样式,如50、50%、50%p,如果是数值,则表示在当前视图的左上角,即原点处加上50px,作为缩放起始点X轴坐标:如果是50%,则表示在当前控件的左上角力加上自己宽度的50%作为缩放起始点X轴坐标;如果是50%p,则表示在当前控件的左上角加上父控件宽度的50%作为缩放起始点X轴坐标。
动画的定义,也可以不用set组合,直接定义单个动画,如
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000" 动画时间,单位毫秒
android:startOffset="1000" 动画延迟执行时间
android:fillBefore="true" 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter="false" 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled="true" 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode="restart" 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount="3" 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator="@android:interpolator/decelerate_quad" 插值器资源
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000" 动画时间,单位毫秒
android:startOffset="1000" 动画延迟执行时间
android:fillBefore="true" 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter="false" 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled="true" 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode="restart" 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount="3" 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator="@android:interpolator/decelerate_quad" 插值器资源
android:fromXScale="float" 起始 X 尺寸偏移,其中 1.0 表示不变
android:toXScale="float" 结束 X 尺寸偏移,其中 1.0 表示不变。
android:fromYScale="float" 起始 Y 尺寸偏移,其中 1.0 表示不变
android:toYScale="float" 结束 Y 尺寸偏移,其中 1.0 表示不变
android:pivotX="float" 在对象缩放时要保持不变的 X 坐标
android:pivotY="float" /> 在对象缩放时要保持不变的 Y 坐标
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000" 动画时间,单位毫秒
android:startOffset="1000" 动画延迟执行时间
android:fillBefore="true" 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter="false" 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled="true" 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode="restart" 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount="3" 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator="@android:interpolator/decelerate_quad" 插值器资源
android:fromXDelta="float" 浮点数或百分比。起始 X 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素宽度的百分比(例如 "5%");或相对于父项宽度的百分比(例如 "5%p")。
android:toXDelta="float" 浮点数或百分比。结束 X 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素宽度的百分比(例如 "5%");或相对于父项宽度的百分比(例如 "5%p")。
android:fromYDelta="float" 浮点数或百分比。起始 Y 偏移量。表示方式:相对于正常位置的像素数(例如 "5");相对于元素高度的百分比(例如 "5%");或相对于父项高度的百分比(例如 "5%p")。
android:toYDelta="float"/>
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000" 动画时间,单位毫秒
android:startOffset="1000" 动画延迟执行时间
android:fillBefore="true" 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter="false" 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled="true" 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode="restart" 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount="3" 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator="@android:interpolator/decelerate_quad" 插值器资源
android:fromDegrees="float" 浮点数。起始角度位置,以度为单位。
android:toDegrees="float" 浮点数。结束角度位置,以度为单位。
android:pivotX="float" 浮点数或百分比。旋转中心的 X 坐标。表示方式:相对于对象左边缘的像素数(例如 "5");相对于对象左边缘的百分比(例如 "5%");或相对于父级容器左边缘的百分比(例如 "5%p")。
android:pivotY="float" />
资源引用:
在 Java 中:R.anim.filename
在 XML 中:@[package:]anim/filename
3.2.2 使用方式
- Android 项目中新建 res/anim/ 目录。
- 新建一个动画的XML文件,该文件必须具有单个根元素:它可以是单个 alpha、scale、translate、rotate 或插值器元素,
也可以是包含这些元素组的 set 元素(可能包含其他 )
<set android:shareInterpolator="false">
<scale
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="1.0"
android:toXScale="1.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="700" />
<set android:interpolator="@android:anim/decelerate_interpolator">
<scale
android:fromXScale="1.4"
android:toXScale="0.0"
android:fromYScale="0.6"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="700"
android:duration="400"
android:fillBefore="false" />
<rotate
android:fromDegrees="0"
android:toDegrees="-45"
android:toYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="700"
android:duration="400" />
</set>
</set>
- 代码引用,开始动画
ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
3.2.3 我们也可以在java代码中直接使用
Animation translateAnimation = new TranslateAnimation(0, 500, 0, 500);
Animation alphaAnimation = new AlphaAnimation(...);
Animation scaleAnimation = new ScaleAnimation(...);
Animation rotateAnimation = new RotateAnimation(...);
translateAnimation.setDuration(3000);
// 固定属性的设置都是在其属性前加“set”,如setDuration()
view.startAnimation(translateAnimation);
上面这些代码也可以通过set进行组合使用
AnimationSet outSet = new AnimationSet(true);
TranslateAnimation animOut = new TranslateAnimation(...);
outSet.addAnimation(animOut);
AlphaAnimation alphaAnimaOut = new AlphaAnimation(1f, 0f);
outSet.addAnimation(alphaAnimaOut);
outSet.setDuration(150L);
view.startAnimation(outSet);
3.3 动画插值器
插值器是在 XML 中定义的一种影响动画变化速率的动画修改器,可让现有的动画效果加速、减速、重复、弹跳等。
插值器通过 android:interpolator 属性应用于动画元素,该属性的值是对插值器资源的引用。
包含有以下类型:
插值器类 | 资源 ID | 描述 |
---|---|---|
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator | 变化速率缓慢开始和结束,但在中间加速 |
AccelerateInterpolator | @android:anim/accelerate_interpolator | 变化率开始缓慢然后加速的插值器 |
AnticipateInterpolator | @android:anim/anticipate_interpolator | 开始向后然后向前猛冲 |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator | 开始向后,然后向前猛冲并超过目标值,最后回到最终值 |
BounceInterpolator | @android:anim/bounce_interpolator | 变化在最后反弹 |
CycleInterpolator | @android:anim/cycle_interpolator | 将动画重复指定的周期数。变化率遵循正弦曲线模式 |
DecelerateInterpolator | @android:anim/decelerate_interpolator | 其变化率开始时很快,然后减速 |
LinearInterpolator | @android:anim/linear_interpolator | 变化率恒定的插值器 |
OvershootInterpolator | @android:anim/overshoot_interpolator | 其中的变化向前猛冲并超过最后一个值,然后返回 |
自定义插值器
如果您对平台提供的插值器不满意,则可以使用修改过的属性创建自定义插值器资源,方式如下:
- Android 项目中新建 res/anim/ 目录。
- 新建一个动画的XML文件,
<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android" 差值器的名字, 实现的名称都以小写字母开头
android:attribute_name="value"
/>
<accelerateDecelerateInterpolator>
变化率在开始和结束时缓慢,但在中间会加快。
无属性。
<accelerateInterpolator>
变化率在开始时较为缓慢,然后会加快。
属性:
android:factor
浮点数。加速率。默认值为 1。
<anticipateInterpolator>
先反向变化,然后再急速正向变化。
属性:
android:tension
浮点数。要应用的张力。默认值为 2。
<anticipateOvershootInterpolator>
先反向变化,再急速正向变化并超过目标值,然后以最终值结束。
属性:
android:tension
浮点数。要应用的张力。默认值为 2。
android:extraTension
浮点数。张力要乘以的倍数。默认值为 1.5。
<bounceInterpolator>
变化会在结束时弹跳。
无属性。
<cycleInterpolator>
按指定的循环次数重复动画。变化率符合正弦曲线图。
属性:
android:cycles
整数。循环次数。默认值为 1。
<decelerateInterpolator>
变化率开始时很快,然后减速。
属性:
android:factor
浮点数。减速率。默认值为 1。
<linearInterpolator>
变化率恒定不变。
无属性。
<overshootInterpolator>
先急速正向变化,再超过最终值,然后回到最终值。
属性:
android:tension
浮点数。要应用的张力。默认值为 2。
如:
<?xml version="1.0" encoding="utf-8"?>
<overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:tension="7.0"
/>
3.4 属性动画
在 XML 中定义的动画,用于在设定的一段时间内修改目标对象的属性,例如背景颜色或 alpha 值。
其对应的java类 ValueAnimator、ObjectAnimator 或 AnimatorSet
xml中定义属性动画
- 新建目录及文件 res/animator/filename.xml
语法如下:
<set
android:ordering=["together" | "sequentially"]> 指定此集合中动画的播放顺序, sequentially 依序播放此集合中的动画。 together(默认) 同时播放此集合中的动画。
<objectAnimator
android:propertyName="string" 要添加动画效果的对象的属性,如"alpha" 或 "backgroundColor"
android:duration="int" 整数。动画的时间,以毫秒为单位。默认为 300 毫秒。
android:valueFrom="float | int | color" 浮点数、整数或颜色。动画属性的起始值。如果未指定,则动画将从属性的 get 方法获得的值开始。颜色以六位十六进制数字表示,例如 #333333。
android:valueTo="float | int | color" 浮点数、整数或颜色。必需。动画属性的结束值。颜色以六位十六进制数字表示,例如 #333333
android:startOffset="int" 整数。调用 start() 后动画延迟的毫秒数
android:repeatCount="int" 整数。动画的重复次数。设为 "-1" 表示无限次重复,也可设为正整数。例如,值 "1" 表示动画在初次播放后重复播放一次,因此动画总共播放两次。默认值为 "0",表示不重复。
android:repeatMode=["restart" | "reverse"] 整数。动画播放到结尾处的行为。android:repeatCount 必须设置为正整数或 "-1",该属性才有效。设置为 "reverse" 可让动画在每次迭代时反向播放,设置为 "restart" 则可让动画每次从头开始循环播放。
android:valueType=["intType" | "floatType"]/> 如果值为颜色,则不要指定此属性。动画框架会自动处理颜色值。 intType 指定动画值为整数。 floatType(默认) 指定动画值为浮点数。
<animator
android: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包裹,定义单一的动画
<objectAnimator
android: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"]/>
<animator
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"]/>
- 资源引用:
在 Java 或 Kotlin 代码中:R.animator.filename
在 XML 中:@[package:]animator/filename
我们举例:
定义xml动画,然后在代码中调用开始动画。
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
开始动画
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.animator.property_animator);
set.setTarget(myObject); // 必须操作
set.start();
代码中定义属性动画
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
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();
这块东西比较多,由于篇幅原因,我们另起一篇。
四、属性动画与视图动画的区别
1、 视图动画系统仅提供为 View 对象添加动画效果的功能,因此,如果您想为非 view 对象添加动画效果,则必须实现自己的代码才能做到。
视图动画系统也存在一些限制,因为它仅公开view 对象的部分方面来供您添加动画效果;例如,您可以对视图的缩放和旋转添加动画效果,但无法对背景颜色这样做。
2、 视图动画系统的另一个缺点是它只会在绘制视图的位置进行修改,而不会修改实际的视图本身。例如,如果您为某个按钮添加了动画效果,使其可以在屏幕上移动,该按钮会正确绘制,
但能够点击按钮的实际位置并不会更改,因此您必须通过实现自己的逻辑来处理此事件。