Android三种动画
三方:https://blog.youkuaiyun.com/zuo_er_lyf/article/details/79716840
Android动画分三类:帧动画(frame animation),补间动画(tween animation),属性动画(property animation)
一、帧动画(frame animation)
1、作用对象:视图控件(view)
1.如Android的TextView、Button等等
2.不可作用于View组件的属性,如:颜色、背景、长度等等
2、原理
- 将动画拆分成帧的形式,每一帧对应一张图片
- 本质就是:按顺序播放一组预先定义好的图片
3、具体使用
步骤①:将序列图片放到drawable中
步骤②:设置启动动画:Java和xml
方式一:XML实现
- step1 在res/drawable中创建动画效果.XML文件
- step2 设置动画资源
music_anim.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/sound_00030"
android:duration="100" />
<item
android:drawable="@drawable/sound_00031"
android:duration="100" />
</animation-list>
- step3 在Java代码中 载入&启动
public class MainActivity extends AppCompatActivity {
private AnimationDrawable animationDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imageview = (ImageView) findViewById(R.id.imageview);
Button btn_start = (Button) findViewById(R.id.btn_start);
Button btn_stop = (Button) findViewById(R.id.btn_stop);
//开启动画
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//设置动画
imageview.setImageResource(R.drawable.music_anim);
//获取动画对象
animationDrawable = (AnimationDrawable) imageview.getDrawable();
//开启动画
animationDrawable.start();
}
});
//停止动画
btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
animationDrawable.stop();
}
});
}
}
方式2:在Java代码中实现
animationDrawable = new AnimationDrawable();
for (int i = 30; i <= 59; i++) {
int id = getResources().getIdentifier("sound" + i, "drawable", getPackageName());
Drawable drawable = getResources().getDrawable(id);
animationDrawable.addFrame(drawable, 1);
}
// <--开始动画-- >
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
animationDrawable.setOneShot(false);
imageview.setImageDrawable(animationDrawable);
// 获取资源对象
animationDrawable.stop(); // 特别注意:在动画start()之前要先stop(),不然在第一次动画之后会停在最后一帧,这样动画就只会触发一次
animationDrawable.start(); // 启动动画 } });
}
});
// <-- 停止动画 -->
btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animationDrawable.stop();
}
});
4、特点
- 优点:使用简单、方便
- 缺点: 容易引起 OOM,因为会使用大量 & 尺寸较大的图片资源
使用时一定注意避免使用大图片,否则会引起OOM
5、应用场景
- 较为复杂的个性化动画效果。
二、补间动画
1、作用对象
- 视图 (view)
1.如Android的TextView、Button等等
2.不可作用于View组件的属性,如:颜色、背景、长度等等
2、原理
- 通过确定开始视图样式&结束视图样式、中间动画变化过程由系统补全来确定一个动画
动效样式有:translation、alpha、scale、rotate
涉及到四个类:TranslateAnimation、AlphaAnimation、RotateAnimation、ScaleAnimation
3、具体使用
- 补间动画使用方式分两种:Java代码&xml中实现
前者优点:动画描述的可读性更好
后者优点:动画效果可动态创建
3.1 平移动画(translate)
方式一:xml中实现
- step1:在res/anim中创建动效.xml文件
- step2:设置平移动画的参数
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:startOffset="1000"
android:fillAfter="false"
android:fillBefore="true"
android:fillEnabled="true"
android:repeatCount="0"
android:repeatMode="restart"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="500"
android:toYDelta="500" />
- step3 在Java代码中创建animation对象&播放动画
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate_animation);
btn_start.startAnimation(animation);
方式二:Java代码中实现
TranslateAnimation translateAnimation = new TranslateAnimation(0, 500, 0, 500);
translateAnimation.setDuration(5000);
translateAnimation.setRepeatMode(Animation.REVERSE);
translateAnimation.setRepeatCount(3);
btn_start.startAnimation(translateAnimation);
3.2 缩放动画(scale)
方式一:xml中实现
- step1:在res/anim中创建动效.xml文件(scale_animation.xml)
- step2:设置缩放动画的参数
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:startOffset="1000"
android:fillAfter="false"
android:fillBefore="true"
android:fillEnabled="true"
android:repeatCount="5"
android:repeatMode="reverse"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:toXScale="2"
android:toYScale="2"
android:pivotX="50%"
android:pivotY="50%"/>
- step3 在Java代码中创建animation对象&播放动画
Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale_animation);
btn_start.startAnimation(animation);
方式二:Java代码中实现
ScaleAnimation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(5000);
btn_start.startAnimation(scaleAnimation);
3.3 旋转动画(rotate)
方式一:xml中实现
- step1:在res/anim中创建动效.xml文件(rotate_animation.xml)
- step2:设置旋转动画的参数
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:startOffset="0"
android:fillAfter="true"
android:fillBefore="false"
android:repeatCount="5"
android:repeatMode="reverse"
android:fromDegrees="30"
android:toDegrees="150"
android:pivotY="50%"
android:pivotX="0"/>
- step3 在Java代码中创建animation对象&播放动画
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate_animation);
btn_start.startAnimation(animation);
方式二:Java代码中实现
RotateAnimation rotateAnimation = new RotateAnimation(30, 150, 0.5f, 0.5f);
rotateAnimation.setRepeatCount(5);
rotateAnimation.setDuration(5000);
rotateAnimation.setRepeatMode(Animation.REVERSE);
btn_start.startAnimation(rotateAnimation);
3.4 透明度动画(alpha)
方式一:xml中实现
- step1:在res/anim中创建动效.xml文件
- step2:设置透明度动画的参数
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="false"
android:fillBefore="true"
android:fillEnabled="true"
android:fromAlpha="0.5"
android:repeatCount="5"
android:repeatMode="reverse"
android:startOffset="1000"
android:toAlpha="3" />
- step3 在Java代码中创建animation对象&播放动画
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate_animation);
btn_start.startAnimation(animation);
方式二:Java代码中实现
AlphaAnimation alphaAnimation = new AlphaAnimation(0.5f, 3.0f);
alphaAnimation.setDuration(5000);
btn_start.startAnimation(alphaAnimation);
5、组合动画set
- 上面讲的都是单个动画效果;而实际中很多需求都需要同时使用平移、缩放、旋转 & 透明度4种动画,即组合动画
- 使用组合动画需要用到标签
方式一:xml中实现
- step1:在res/anim中创建动效.xml文件
- step2:设置组合动画的参数
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="false"
android:fillBefore="true"
android:fillEnabled="true"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:startOffset="1000">
<rotate
android:duration="1000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toDegrees="360" />
// 设置平移动画,语法同单个动画
<translate
android:duration="10000"
android:fromXDelta="-50%p"
android:fromYDelta="0"
android:startOffset="1000"
android:toXDelta="50%p"
android:toYDelta="0" />
// 设置透明度动画,语法同单个动画
<alpha
android:duration="3000"
android:fromAlpha="1.0"
android:startOffset="7000"
android:toAlpha="0.0" />
// 设置缩放动画,语法同单个动画
<scale
android:duration="1000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="4000"
android:toXScale="0.5"
android:toYScale="0.5" />
</set>
组合动画独特的属性 android:shareinterpolator = “true”
如果集合不指定插值器,那么子动画需要单独设置
组合动画播放时是全部动画同时开始
如果想不同动画不同时间开始就要使用android:startOffset属性来延迟单个动画播放时间
- step3 在Java代码中创建animation对象&播放动画
Animation animation = AnimationUtils.loadAnimation(this, R.anim.set_animation);
btn_start.startAnimation(animation);
方式二:Java代码中实现
//集合动画对象创建
AnimationSet animationSet = new AnimationSet(true);
animationSet.setRepeatMode(Animation.REVERSE);
animationSet.setRepeatCount(1);
//旋转动画对象创建
Animation rotate = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(1000);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
//透明度动画对象创建
Animation alpha = new AlphaAnimation(1, 0);
alpha.setDuration(3000);
alpha.setStartOffset(7000);
//平移动画对象创建
Animation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT, -0.5f, TranslateAnimation.RELATIVE_TO_PARENT, 0.5f, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, 0);
translate.setDuration(10000);
//缩放动画对象创建
Animation scale1 = new ScaleAnimation(1, 0.5f, 1, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scale1.setDuration(1000);
scale1.setStartOffset(4000);
//将创建每一种子动画添加到组合动画
animationSet.addAnimation(alpha);
animationSet.addAnimation(rotate);
animationSet.addAnimation(translate);
animationSet.addAnimation(scale1);
//开启动画
btn_start.setAnimation(animationSet);
6、动画监听
alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
7、应用场景
- 7.1 标准的动画效果
补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度; - 7.2 特殊的应用场景
Activity 的切换效果
Fragement 的切换效果
视图组(ViewGroup)中子元素的出场效果
三、属性动画(Property Animation)
1、简介:属性动画是在Android3.0(API11)提出的全新的动画
2、出现原因:解决帧动画与补间动画的不足
- ①作用对象单一:只能作用于view
- ②没有改变view的属性,只是改变视觉效果
- ③动画效果单一
3、定义:作用于任意对象,实现各种自定义动画效果
4、工作原理:在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果
有两个很重要的类ValueAnimator 类 & ObjectAnimator 类
5、具体使用
5.1 ValueAnimator类
定义: 属性动画中最核心的一个类
原理: 通过不断控制 值 的变化,再不断 手动 赋给对象的属性,从而实现动画效果
ValueAnimator中有三个重要的方法实现动画:
- ValueAnimator.ofInt(int… values)
- ValueAnimator.ofFloat(float… values)
- ValueAnimator.ofObject(int… values)
5.1.1 ValueAnimator.ofInt(int… values)
作用:将初始值以整型的形式过度到结束值
估值器默认是整形估值器IntEvaluator
具体使用
//属性动画
//step1 设置属性动画的初始值与结束值
ValueAnimator valueAnimator = ValueAnimator.ofInt(btn_property_animation.getLayoutParams().width, 1000);
// ofInt()作用有两个
// 1. 创建动画实例
// 2. 将传入的多个Int参数进行平滑过渡:此处传入0和1,表示将值从0平滑过渡到1 // 如果传入了3个Int参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,以此类推
// ValueAnimator.ofInt()内置了整型估值器,直接采用默认的.不需要设置,即默认设置了如何从初始值 过渡到 结束值
//step2 设置动画的各种属性
//设置动画运行时长
valueAnimator.setDuration(5000);
//设置动画启动延时时长
valueAnimator.setStartDelay(500);
//设置动画重复次数=次数+1
//动画次数=infinite 动画无限重复
valueAnimator.setRepeatCount(6);
// 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
//step3 将改变的值手动赋给对象的属性:通过动画的更新监听器
//值每改变一次,方法就回被调用一次
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//获得变化后的属性
int curValue = (int) valueAnimator.getAnimatedValue();
//值每次更改后手动赋给按钮
btn_property_animation.getLayoutParams().width = curValue;
//刷新视图,重新绘制
btn_property_animation.requestLayout();
}
});
valueAnimator.start();
5.1.2 ValueAnimator.ofFloat(float… values)
作用:将初始值以浮点型的形式过度到结束值
估值器默认是浮点型估值器FloatEvaluator
具体使用:与ofInt一样
5.1.3 ValueAnimator.ofObject(int… values)
作用:将初始值以对象的形式过度到结束值
通过操作对象实现动画
具体使用
// 创建初始动画时的对象 & 结束动画时的对象
myObject object1 = new myObject();
ValueAnimator anim = ValueAnimator.ofObject(new myObjectEvaluator(), object1, object2);
// 创建动画对象 & 设置参数
// 参数说明
// 参数1:自定义的估值器对象(TypeEvaluator 类型参数)
// 参数2:初始动画的对象
// 参数3:结束动画的对象
anim.setDuration(5000);
anim.start();
实例演示
~~~~~step1:定义对象类
因为ValueAnimator.ofObject()是面向对象操作的,所以需要自定义对象类
public class MyPoint {
private float x;
private float y;
public MyPoint(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
- ~~~~~step2:根据需求实现估值器借口TypeEvaluator
public class PiontEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
//将初始值和结束值抢转成point类型
MyPoint startPoint = (MyPoint) startValue;
MyPoint endPoint = (MyPoint) endValue;
//根据fraction计算当前动画的x和y值
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
//将计算后的坐标封装到一个新的point对象中,然后返回
MyPoint point = new MyPoint(x, y);
return point;
}
}
- ~~~~~step3:将属性动画作用到自定义的view上
public class MyView extends View {
//需要用到的变量
private static final float RADIUS = 70f;
private MyPoint curPoint;
private Paint mPaint;
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.GREEN);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//如果当前坐标为空(第一次)
if (curPoint == null) {
//创建一个点对象
MyPoint point = new MyPoint(RADIUS, RADIUS);
//在该点画一个圆:圆心(80,80),半径80
float x = point.getX();
float y = point.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
//将属性动画作用到view中
MyPoint startPoint = new MyPoint(RADIUS, RADIUS);
MyPoint endPoint = new MyPoint(700, 1000);
//创建动画对象,设置初始值和结束值
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PiontEvaluator(), startPoint, endPoint);
valueAnimator.setDuration(5000);
//给动画添加更新 监听器
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
curPoint = (MyPoint) valueAnimator.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
} else {
//当前坐标为空
float y = curPoint.getY();
float x = curPoint.getX();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
}
}
- ~~~~~step4:在布局中加入自定义view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="40dp"
tools:context="com.yunjiai.admin.animation.MainActivity">
<com.yunjiai.admin.animation.MyView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
5.2 ObjectAnimator类
5.2.1原理: 通过不断控制 值 的变化,再不断 自动 赋给对象的属性,从而实现动画效果
如直接改变 View的 alpha 属性 从而实现透明度的动画效果
继承自ValueAnimator类,即底层的动画实现机制是基于ValueAnimator类
ObjectAnimator与 ValueAnimator类的区别:
- ValueAnimator 类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;
- ObjectAnimator 类是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作;
5.2.2 具体使用
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values);
// ofFloat()作用有两个
// 1. 创建动画实例
// 2. 参数设置:参数说明如下
// Object object:需要操作的对象
// String property:需要操作的对象的属性
// float ....values:动画初始值 & 结束值(不固定长度)
// 若是两个参数a,b,则动画效果则是从属性的a值到b值
// 若是三个参数a,b,c,则则动画效果则是从属性的a值到b值再到c值
// 以此类推
// 至于如何从初始值 过渡到 结束值,同样是由估值器决定,此处ObjectAnimator.ofFloat()是有系统内置的浮点型估值器FloatEvaluator,同ValueAnimator讲解
anim.setDuration(500); // 设置动画运行的时长
anim.setStartDelay(500); // 设置动画延迟播放时间
anim.setRepeatCount(0); // 设置动画重复播放次数 = 重放次数+1 // 动画播放次数 = infinite时,动画无限重复
anim.setRepeatMode(ValueAnimator.RESTART); // 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放 // ValueAnimator.REVERSE:倒序回放
animator.start(); // 启动动画
5.2.3 使用实例
- 平移
//获得当前按钮的位置
float curX = btn_property_animation.getTranslationX();
ObjectAnimator alpha = ObjectAnimator.ofFloat(btn_property_animation, "translationX",curX, 360,720);
alpha.setDuration(5000);
alpha.setRepeatCount(10);
alpha.setRepeatMode(ValueAnimator.REVERSE);
alpha.start();
- 旋转
ObjectAnimator alpha = ObjectAnimator.ofFloat(btn_property_animation, "rotation",0, 360,720);
alpha.setDuration(5000);
alpha.setRepeatCount(10);
alpha.setRepeatMode(ValueAnimator.REVERSE);
alpha.start();
- 透明度
ObjectAnimator alpha = ObjectAnimator.ofFloat(btn_property_animation, "alpha",0f, 1f);
alpha.setDuration(5000);
alpha.setRepeatCount(10);
alpha.setRepeatMode(ValueAnimator.REVERSE);
alpha.start();
- 缩放
ObjectAnimator alpha = ObjectAnimator.ofFloat(btn_property_animation, "scaleY",1f, 2f,3f,5f,1f,0.2f);
alpha.setDuration(5000);
alpha.setRepeatCount(10);
alpha.setRepeatMode(ValueAnimator.REVERSE);
alpha.start();
从上边的例子可以看出只要改变ObjectAnimator.ofFLoat()中的第二个参数就可以实现各种动画,下边是补充属性:
属性 | 作用 | 数值类型 |
---|---|---|
Alpha | 控制View的透明度 | float |
TranslationX | 控制X方向的位移 | float |
TranslationY | 控制Y方向的位移 | float |
ScaleX | 控制X方向的缩放倍数 | float |
ScaleY | 控制Y方向的缩放倍数 | float |
Rotation | 控制以屏幕方向为轴的旋转度数 | float |
RotationX | 控制以X轴为轴的旋转度数 | float |
RotationY | 控制以Y轴为轴的旋转度数 | float |