深入浅析Android开发动画
目录
一、View动画
View动画包括:补间动画、逐帧动画。
1.1 补间动画
作用对象:View
动画效果:平移、缩放、旋转、透明度
名称 | 子类 | 效果 |
---|---|---|
平移动画 | TranslateAnimation | 移动View |
缩放动画 | ScaleAnimation | 放大/缩小View |
旋转动画 | RotateAnimation | 旋转View |
透明度动画 | AlphaAnimation | 改变View的透明度 |
四种动画xml代码
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
android:interpolator = "@android:anim/linear_interpolator">
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:fromYDelta="float"
android:toXDelta="float"
android:toYDelta="float" />
<alpha
android:fromAlpha="float"
android:toAlpha="float"/>
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float"/>
</set>
以下是对上面代码的说明。
1.set
:表示动画集合,对应AnimationSet
类
-
interpolator
:表示动画集合所采用的插值器,影响动画的速度。可以不指定,默认是accelerate_decelerate_interpolate
(加速减速插值器)。下文属性动画
会详细介绍插值器的相关知识。 -
shareInterpolator
:表示集合中的动画是否和集合共享一个插值器。如果集合不指定插值器, 那么子动画就需要单独制定所需的插值器或者使用默认值。 -
fillAfter
:表示动画结束时是否保持动画结束时的状态
2.rotate
:表示旋转动画,对应RotateAnimation
类。
-
fromDegrees
:动画起始时物件的角度 (0度指X轴正方向所在方向) -
toDegrees
:动画结束时物件旋转的角度
以上两个属性共同确定旋转方向,原则是:当角度(to-from)为负数时表示逆时针旋转,反之。
-
pivotY
:动画旋转的轴点的X坐标 -
pivotX
:动画旋转的轴点的Y坐标
3.translate
:表示平移动画,对应TranslateAnimation
类
-
android:fromXDelta
:动画起始时X坐标上的位置。 -
android:toXDelta
:动画结束时X坐标上的位置。 -
android:fromYDelta
:动画起始时Y坐标上的位置。 -
android:toYDelta
:动画结束时Y坐标上的位置。
注意:以上四个属性以及后面几个类似属性的取值可能是数值、百分数、百分数p,各自含义是:
- 50:以View左上角为原点沿坐标轴正方向偏移50px。
- 50%:以View左上角为原点沿坐标轴正方向偏移View宽/高度的50%。
- 50%p:以View左上角为原点沿坐标轴正方向偏移父(parent)控件宽/高度的50%。区别如图:
4.alpha
:表示透明度动画,对应AlphaAnimation
类
-
fromAlpha
:动画起始时透明度 -
toAlpha
:动画结束时透明度
以上两个属性值:从0-1中取值。注意:
- 值=0.0 :表示完全透明
- 值=1.0 :表示完全不透明
5.scale
:表示缩放动画,对应ScaleAnimation
类
-
fromXScale
:动画起始时X坐标上的伸缩尺寸 -
toXScale
:动画结束时X坐标上的伸缩尺寸 -
fromYScale
:动画起始时Y坐标上的伸缩尺寸 -
toYScale
:属性为动画结束时Y坐标上的伸缩尺寸
以上四个属性值的值含义:
- 值=0.0 :表示收缩到没有
- 值<1.0 :表示收缩
- 值=1.0 :表示无伸缩
- 值>1.0 :表示放大
-
pivotX
:动画相对于物件的X坐标的开始位置 -
pivotY
:动画相对于物件的Y坐标的开始位置
以上两个属性值表示缩放的轴点:从0%-100%中取值。
1.1.1 单个动画使用
在XML/Java代码中设置,在XML中设置,动画描述的可读性更好。在Java代码中设置,动画效果可动态创建。
以平移动画为例;
XML设置法
- 步骤1:xml设置
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000" //动画持续时间
android:startOffset ="1000"// 动画延迟开始时间(ms)
android:fillBefore = "true"// 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter = "false"// 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled= "true"// 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode="restart"// 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount = "0"重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:fromXDelta="0"// 视图在水平方向x 移动的起始值
android:toXDelta="500"// 视图在水平方向x 移动的结束值
android:fromYDelta="0"// 视图在竖直方向y 移动的起始值
android:toYDelta="0" // 视图在竖直方向y 移动的结束值
/>
- 步骤2:java代码
public class MainActivity extends AppCompatActivity {
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
final Animation animation = AnimationUtils.loadAnimation(this,R.anim.animation); //创建动画对象,传入xml文件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button.startAnimation(animation); //启动动画
}
});
}
}
- 效果图
Java代码设置法
Button mButton = (Button) findViewById(R.id.Button);
// 步骤1:创建 需要设置动画的 视图View
Animation translateAnimation = new TranslateAnimation(0,500,0,0);
// 步骤2:创建平移动画的对象:平移动画对应的Animation子类为TranslateAnimation
// 参数分别是:
// 1. fromXDelta :视图在水平方向x 移动的起始值
// 2. toXDelta :视图在水平方向x 移动的结束值
// 3. fromYDelta :视图在竖直方向y 移动的起始值
// 4. toYDelta:视图在竖直方向y 移动的结束值
translateAnimation.setDuration(3000);
// 固定属性的设置都是在其属性前加“set”,如setDuration()
mButton.startAnimation(translateAnimation);
// 步骤3:播放动画
效果图跟上图一样。
1.1.2 组合动画使用
- 步骤1:XML设置
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:startOffset ="0"
android:fillBefore = "true"
android:fillAfter = "false"
android:fillEnabled= "true"
android:repeatMode="restart"
android:repeatCount = "0"
android:interpolator = "@android:anim/linear_interpolator">
<rotate //旋转动画
android:duration="1000"
android:fromDegrees="0"// 动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
android:toDegrees="360"// 动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
android:pivotX="50%"// 旋转轴点的x坐标
android:pivotY="50%"// 旋转轴点的y坐标
android:repeatMode="restart"
android:repeatCount="infinite"
/>
<translate //平移动画
android:duration="10000"
android:startOffset ="1000"
android:fromXDelta="-50%p"
android:fromYDelta="0"
android:toXDelta="50%p"
android:toYDelta="0" />
</set>
- 步骤2:Java代码设置
public class MainActivity extends AppCompatActivity {
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.button);
final Animation animation = AnimationUtils.loadAnimation(this,R.anim.group_animation); //创建动画对象,传入xml文件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button.startAnimation(animation); //启动动画
}
});
}
}
- 效果图
1.2 逐帧动画
使用对象:View
原理:将动画拆分为帧的形式,且定义每一帧 = 每一张图片
本质:顺序播放一组预先定义好的图片
使用
-
步骤1: 在
res/anim
文件夹中创建xml
文件<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true" // 设置是否只播放一次,默认为false > // item = 动画图片资源;duration = 设置一帧持续时间(ms) <item android:drawable="@drawable/a0" android:duration="100"/> <item android:drawable="@drawable/a1" android:duration="100"/> <item android:drawable="@drawable/a2" android:duration="100"/> <item android:drawable="@drawable/a3" android:duration="100"/> </animation-list>
-
步骤二:在Java代码中设置
Button button = findViewById(R.id.button);
button.setBackgroundResource(R.drawable.frame_animation);
AnimationDrawable animationDrawable = (AnimationDrawable) button.getBackground();
animationDrawable.start(); //启动动画
优点:使用简单、方便
缺点:容易引起
OOM
,当使用大量 和尺寸较大的图片资源时。
二、属性动画
说明:属性动画(
Property Animation
)是在Android 3.0
(API 11
)后才提供的一种全新动画模式。
Q:为什么要提供属性动画?
- View动画作用对象局限于View,而属性动画能作用于任意Java对象。
- View动画只是改变了View的视觉效果,没有改变View的属性,属性动画可以改变对象的属性。
- View动画效果单一,属性动画效果更加丰富。
View动画 | 属性动画 | |
---|---|---|
作用对象 | View | 任何对象,甚至没有对象 |
属性改变 | 没有改变属性 | 改变了属性 |
动画效果 | 效果单一 | 效果丰富 |
属性改变说明:比如将屏幕左上角的按钮通过补间动画移动到屏幕右下角,点击当前按钮位置(右下角)是没有效果的,实际上按钮还是停留在左上角,补间动画只是将按钮绘制到屏幕右下角,改变了视觉效果而已。
2.1 使用
同样的,属性动画可以在xml设置实,也可以在代码中设置实现。建议用代码实现:
- 代码实现比较简单。
- 属性的起始值有时候无法确定,需要动态地创建属性动画。
下面是组合动画旋转+平移实例。
Java 设置
button = findViewById(R.id.button);
// 步骤1:设置需要组合的动画效果
// 平移动画
ObjectAnimator translation = ObjectAnimator.ofFloat(button, "translationX", 0, 300);
translation.setRepeatCount(0);
// 旋转动画
ObjectAnimator rotate = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);
// 步骤2:创建组合动画的对象
final AnimatorSet animSet = new AnimatorSet();
// 步骤3:根据需求组合动画
animSet.play(translation).with(rotate);
// 步骤4:启动动画
animSet.start();
XML设置
- 步骤1:XML设置
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >
// 表示Set集合内的动画按顺序进行
// ordering的属性值:sequentially & together
// sequentially:表示set中的动画,按照先后顺序逐步进行(a 完成之后进行 b )
// together:表示set中的动画,在同一时间同时进行,为默认值
<set android:ordering="together" >
// 下面的动画同时进行
<objectAnimator
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="0"
android:valueTo="300"
android:valueType="floatType" >
</objectAnimator>
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
</objectAnimator>
</set>
</set>
- Java代码设置
AnimatorSet set = (AnimatorSet)AnimatorInflater.loadAnimator(this,R.anim.property_animator);
set.setTarget(button); //设置动画作用对象
set.start();//启动动画
- 效果图
2.2 插值器与估值器
类型 | 定义 | 作用 | 应用场景 | 备注 |
---|---|---|---|---|
插值器 | 辅助动画实现的接口 | 设置属性值从初始值过渡到结束值的变化规律 | 实现非线性运动的动画效果 | 内置9种插值器/自定义插值器实现 |
估值器 | 辅助动画插值器的接口 | 设置属性值从初始值过渡到结束值的变化具体数值 | 协助插值器 实现非线性运动的动画效果 | 内置3种估值器/自定义估值器实现 |
插值器
//xml设置
android:interpolator="@android:anim/overshoot_interpolator"
//Java代码设置
Interpolator overshootInterpolator = new OvershootInterpolator();
animation.setInterpolator(overshootInterpolator);
估值器
- 作用:根据当前属性改变的百分比计算出改变后的属性值。
- 常用的系统内置的估值器:
- 整型估值器(
IntEvaluator
)- 浮点型估值器(
FloatEvaluator
)- Color属性估值器(
ArgbEvaluator
)
- 仅针对于属性动画,View动画不需要类型估值器。是属性动画实现非匀速动画的重要手段。
- 自定义插值器方法:实现
Interpolator
/TimeInterpolator
接口 ,然后复写getInterpolation()
- 自定义估值器方法:实现
TypeEvaluator
接口,然后复写evaluate()
。
推荐一篇插值器估值器的详细用法Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)
2.3 监听器
Animation.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animation animation) {
//动画开始时执行
}
@Override
public void onAnimationRepeat(Animation animation) {
//动画重复时执行
}
@Override
public void onAnimationCancel()(Animation animation) {
//动画取消时执行
}
@Override
public void onAnimationEnd(Animation animation) {
//动画结束时执行
}
});
// 特别注意:每次监听必须4个方法都重写。
Q:有些时候我们并不需要监听动画的所有时刻,不想写太多代码怎么办?
采用动画适配器(AnimatorListenerAdapter
)。
anim.addListener(new AnimatorListenerAdapter() {
// 向addListener()方法中传入适配器对象AnimatorListenerAdapter()
// 由于AnimatorListenerAdapter中已经实现好每个接口
// 所以这里不实现全部方法也不会报错
@Override
public void onAnimationStart(Animator animation) {
// 如想只想监听动画开始时刻,就只需要单独重写该方法就可以
}
});
三、总结
ObjectAnimator
与ValueAnimator
类的区别:
ValueAnimator
类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;ObjectAnimator
类是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作;
ValueAnimator
类自动赋值的逻辑:
-
初始化时,如果属性的初始值没有提供,则调用属性的
get()
进行取值; -
当 值 变化时,用对象该属性的
set()
方法,从而从而将新的属性值设置给对象属性。
-
ObjectAnimator
类针对的是任意对象 & 任意属性值,并不是单单针对于View对象 -
如果需要采用
ObjectAnimator
类实现动画效果,那么需要操作的对象就必须有该属性的set() & get()
-
同理,针对上述另外的三种基本动画效果,
View
也存在着setRotation()
、getRotation()
、setTranslationX()
、getTranslationX()
、setScaleY()
、getScaleY()
等set()
&get()
。
本文参考自:
- 《Android开发艺术探索》
- 《Android进阶之光》
- Android动画:这是一份全面 & 详细的动画使用攻略
- 进阶之路 | 奇妙的Animation之旅
本文地址:https://blog.csdn.net/qq_44830568/article/details/109059720