动画

Android动画分为两类,传统动画属性动画(android3.0之后出现)

传统动画

帧动画

帧动画是简单的动画,通过播放一张张图片来实现动画效果,相当于gif效果
很经典的loading加载效果就是帧动画

在Drawable文件夹下创建xml文件:

1
2
3
4
5
6
7
8
9
<?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/ic_loading1" android:duration="150"></item>
<item android:drawable="@drawable/ic_loading2" android:duration="150"></item>
<item android:drawable="@drawable/ic_loading3" android:duration="150"></item>
</animation-list>

android:oneshot=”false” ,动画执行一次(true)还是循环执行多次

javacode中引用该动画:

1
2
3
4
ImageView imageView = new ImageView(mContext);
imageView.setImageResource(R.drawable.loading);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();

补间动画

补间动画又可以分为四种,分别是 alpha(淡入淡出)translate(位移)scale(缩放大小)rotate(旋转)
补间动画的实现,一般使用xml 文件的形式,代码会更容易书写和阅读,同时也更容易复用。
在res/anim文件夹下创建相应的xml文件(如果没有anim文件夹则右击res创建,使用整个文件夹的复制黏贴容易出现资源路径没找到问题)

alpha_anim.xml 动画实现

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="0.0" />

android:fromAlpha 动画开始的透明度
android:toAlpha 动画结束时的透明度
值都是从0.0-1.0,0.0为全透明 1.0为完全不透明

scale.xml 动画实现

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0"/>

android:fromXScale 起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍
android:toXScale 结尾的X方向上相对自身的缩放比例,浮点值
android:fromYScale 起始的Y方向上相对自身的缩放比例,浮点值
android:toYScale 结尾的Y方向上相对自身的缩放比例,浮点值
android:pivotX和android:pivotY 下文统一做说明

translate.xml 动画实现

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>  
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:toXDelta="50%"
android:fromYDelta="0"
android:toYDelta="30%"
android:duration="1000"
android:fillAfter="true"></translate>

android:fromXDelta 起始点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,具体意义已在scale标签中讲述,这里就不再重讲
android:fromYDelta 起始点Y轴从标,可以是数值、百分数、百分数p 三种样式;
android:toXDelta 结束点X轴坐标
android:toYDelta 结束点Y轴坐标

rotate.xml 动画实现

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>  
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="-650"
android:pivotX="50%"
android:pivotY="50%"
android:duration="3000"
android:fillAfter="true">
</rotate>

android:fromDegrees 开始旋转的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数
android:toDegrees 结束时旋转到的角度位置,正值代表顺时针方向度数,负值代码逆时针方向度数

使用set 标签将多个动画组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<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" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>

javacode中引用:

1
2
3
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
ImageView imageView = (ImageView) findViewById(R.id.anim_iv);
imageView.startAnimation(animation);

一些重要属性
android:duration 动画持续时间,以毫秒为单位
android:fillAfter 如果设置为true,控件动画结束时,将保持动画最后时的状态
android:fillBefore 如果设置为true,控件动画结束时,还原到开始动画前的状态
android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
android:repeatCount 重复次数
android:repeatMode 重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果
android:interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果

pivot属性是很重要的属性 决定了当前动画执行的参考位置

以pivotX为例:
pivotX取值 10 表示距离动画所在view自身左边缘10像素
pivotX取值 10% 表示距离动画所在view自身左边缘 的距离是整个view宽度的10%
pivotX取值 10%p 表示距离动画所在view父控件左边缘的距离是整个view宽度的10%

帧动画和补间动画组合使用
两种动画组合使用适合在java代码里面设置,计算好两种动画的执行时间关系即可
例如下面的动画效果:
anim

javacode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private void startAnim()
{

mLoadIv.setImageResource(R.drawable.loading);
mAnimationDrawable = (AnimationDrawable) mLoadIv.getDrawable();
mAnimationDrawable.start();

int translate = DeviceUtil.dip2px(mContext,40);
mAnimationSet = new AnimationSet(true);
TranslateAnimation translateAnimation = new TranslateAnimation(0f, 0f, -translate, translate);
//动画重复次数 无限循环
translateAnimation.setRepeatCount(Animation.INFINITE);
//设置重复模式 倒序播放
translateAnimation.setRepeatMode(Animation.REVERSE);
translateAnimation.setInterpolator(new OvershootInterpolator());
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.1f, 1.0f, 0.9f);
//动画重复次数 无限循环
scaleAnimation.setRepeatCount(Animation.INFINITE);
//设置重复模式 倒序播放
scaleAnimation.setRepeatMode(Animation.REVERSE);
scaleAnimation.setInterpolator(new OvershootInterpolator());
mAnimationSet.addAnimation(translateAnimation);
mAnimationSet.addAnimation(scaleAnimation);
mAnimationSet.setDuration(400);
mLoadIv.setAnimation(mAnimationSet);
mAnimationSet.start();

handler.post( new Runnable(){
private int k = 0;
public void run() {
k++;
String text = "";
if(k%3 == 0)
{
text = ".";
}else if(k%3 == 1)
{
text = "..";
}else if(k%3 == 2)
{
text = "...";
}
mLoadTv.setText(text);
handler.postDelayed(this, 500);
}
});

}

属性动画

属性动画当然也可以使用xml文件的方式实现,然而属性动画的属性值通常会引用对象具体的属性,所以通过代码动态获取会更方便开发。

属性动画实现上面补间动画的效果

1
2
3
4
5
6
7
private void AlpahAnimation() {
ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
anim.setRepeatCount(-1);
anim.setRepeatMode(ObjectAnimator.REVERSE);
anim.setDuration(1000);
anim.start();
}

可以看到,属性对象可以是具体的view控件对象,可以处理更多的细节

属性动画也是可以组合实现

1
2
3
4
5
6
7
8
9
10
11
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.1f, 0.5f, 0.8f, 1.0f);
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.2f, 1.0f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.5f, 2.0f);
ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 300);
ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 550);
AnimatorSet set = new AnimatorSet();
set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
// set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
set.setDuration(2000);
set.start();

这些动画可以设置为同时播放,或者是按序播放

核心原理

属性动画经常使用到ObjectAnimator 这个类,
继承自ValueAnimator,可以对任意对象的任意属性进行动画操作
ValueAnimator是整个属性动画机制当中最核心的一个类

属性动画的运行机制是通过不断地对值进行操作来实现的,
而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。
它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,
我们只需要将初始值和结束值提供给ValueAnimator,
并且告诉它动画所需运行的时长,
那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。
除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。

比如以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
mLoadMoreAnimator = ValueAnimator.ofInt(startValue, targetPosition);
mLoadMoreAnimator.setDuration(mHTViewHolder.getAnimationTime());
mLoadMoreAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
int padding = (int) animation.getAnimatedValue();
mLoadMoreContainerView.setPadding(mHTOrientation == HTOrientation.HORIZONTAL_LEFT ? padding : 0, mHTOrientation == HTOrientation.VERTICAL_UP ? padding : 0, mHTOrientation == HTOrientation.HORIZONTAL_RIGHT ? padding : 0, mHTOrientation == HTOrientation.VERTICAL_DOWN ? padding : 0);
}
});
if (animatorListener != null) {
mLoadMoreAnimator.addListener(animatorListener);
}

可以通过设置属性动画来控制页面的平缓移动效果,并且可以监听动画的开始,结束等事件。

属性动画在开发过程中,以后遇到再慢慢补充。

注意事项

使用帧动画时需要注意,不要使用过多特别大的图,容易导致内存不足

使用动画时,记得在合适的时机停止动画,释放动画资源,特别是属性动画,在activity退出时候没有及时停止动画将导致无法释放而导致内存溢出。

坚持原创分享,您的支持将鼓励我继续创作!