一 动画的分类
在Android动画中,总共有两种类型的动画View Animation(视图动画)和Property Animator(属性动画)。
- 视图动画包括Tween Animation(补间动画)和Frame
Animation(逐帧动画)。Tween 动画可以使视图组件移动、缩放,旋转以及产生透明度的变化;Frame动画就是将一个完整的动画拆分成一张张单独的图片,然后再顺序的播放这些排列好的图片,类似于动画片的工作原理。 - 属性动画包括ValueAnimator和ObjectAnimator
二 属性动画和其他动画的区别
第一点从直观上看,他们有如下三点不同:
- 引入时间不同:View Animation是API Level 1就引入的。Property Animation是API Level 11引入的,即Android 3.0才开始有Property Animation相关的API。
- 所在包名不同:View Animation在包android.view.animation中。而Property Animation API在包 android.animation中。
- 动画类的命名不同:View Animation中动画类取名都叫XXXXAnimation,而在Property Animator中动画类的取名则叫XXXXAnimator
大家都知道逐帧动画主要是用来实现动画的,而补间动画才能实现控件的渐入渐出、移动、旋转和缩放的;而Property Animator是在Android 3.0版本才引入的,之前是没有的。大家可能会觉得补间动画和逐帧动画已经很全了,为什么还要引入Property Animator呢?
我提出一个假设:请问大家,如何利用补间动画来将一个控件的背景色在一分钟内从绿色变为红色?这个效果想必没办法仅仅通过改变控件的渐入渐出、移动、旋转和缩放来实现吧,而这个效果是可以通过Property Animator完美实现的
这就是第一个原因:Property Animator能实现补间动画无法实现的功能
大家都知道,补间动画和逐帧动画统称为View Animation,也就是说这两个动画只能对派生自View的控件实例起作用;而Property Animator则不同,从名字中可以看出属性动画,应该是作用于控件属性的!正因为属性动画能够只针对控件的某一个属性来做动画,所以也就造就了他能单独改变控件的某一个属性的值!比如颜色!这就是Property Animator能实现补间动画无法实现的功能的最重要原因。
- 因此我们得到了第二点不同:View Animation仅能对指定的控件做动画,而Property Animator是通过改变控件某一属性值来做动画的。
假设我们将一个按钮从左上角利用补间动画将其移动到右下角,在移动过程中和移动后,这个按钮都是不会响应点击事件的。这是为什么呢?因为补间动画仅仅转变的是控件的显示位置而已,并没有改变控件本身的值。View Animation的动画实现是通过其Parent View实现的,在View被drawn时Parents View改变它的绘制参数,这样虽然View的大小或旋转角度等改变了,但View的实际属性没变,所以有效区域还是应用动画之前的区域;我们看到的效果仅仅是系统作用在按钮上的显示效果,利用动画把按钮从原来的位置移到了右下角,但按钮内部的任何值是没有变化的,所以按钮所捕捉的点击区域仍是原来的点击区域。
- 这就得到了第三点不同:补间动画虽能对控件做动画,但并没有改变控件内部的属性值。这也是视图动画的一个非常大的缺点:不具备交互性,当某个元素发生视图动画后,其响应事件的位置依然在动画前的位置。而Property Animator则是恰恰相反,Property Animator是通过改变控件内部的属性值来达到动画效果的。
三 动画的使用
帧动画实现wifi信号跳动
1.首先在res/drawabl目录下创建一个帧动画的的xml文件
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon1" android:duration="200"></item>
<item android:drawable="@drawable/icon2" android:duration="200"></item>
<item android:drawable="@drawable/icon3" android:duration="200"></item>
<item android:drawable="@drawable/icon4" android:duration="200"></item>
<item android:drawable="@drawable/icon5" android:duration="200"></item>
<item android:drawable="@drawable/icon6" android:duration="200"></item>
</animation-list>
2.给ImageView设置帧动画
<ImageView
android:id="@+id/iv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/frame_anim"
/>
3.获取AnimationDrawable类,执行开始方法
public class MainActivity extends AppCompatActivity {
private ImageView mImageView;
private AnimationDrawable mAnimationDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_show);
}
public void start(View view){
//通过ImageView获取到帧动画的核心类
mAnimationDrawable = (AnimationDrawable) mImageView.getDrawable();
mAnimationDrawable.start();//一旦开始了就不会自动停止,就算设置成了只播放一次
}
public void stop(View view){
if (mAnimationDrawable.isRunning()) {
mAnimationDrawable.stop();//手动停止动画
}
}
}
补间动画
作用在任意view控件,有透明,平移,缩放,旋转四种效果,当然也可以使用动画集合,这些效果都可以通过代码和xml文件两种方式实现。
1.代码动态实现
public void alpha(View view) {
/*
* 从一个透明度到另外一个透明度 范围【0,1】 1.0 代表完全不透明,就是完全可见 0.0代表完全透明,就是完全不可见
*/
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
// 设置时间
alphaAnimation.setDuration(100);// 毫秒 动画的时长
// iv.setAnimation(alphaAnimation);//将动画设置给控件
//
// alphaAnimation.start();//启动动画 //这两行代码不兼容Android4.4
// 重复无限次
alphaAnimation.setRepeatCount(Animation.INFINITE);
alphaAnimation.setRepeatMode(Animation.REVERSE);// 设置重复的策略,逆向
iv.startAnimation(alphaAnimation);// 兼容性强
}
public void translate(View view) {
/*
* 参数1:x方向的参照物
*/
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0.7f, Animation.RELATIVE_TO_SELF, 0, AlphaAnimation.RELATIVE_TO_SELF, 0);
translateAnimation.setDuration(5000);
translateAnimation.setRepeatMode(Animation.REVERSE);
translateAnimation.setRepeatCount(Animation.INFINITE);
// iv.startAnimation(translateAnimation);
rootView.startAnimation(translateAnimation);
}
public void scale(View view) {
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 15f, 0.5f, 15, Animation.RELATIVE_TO_SELF, 0.45f, Animation.RELATIVE_TO_SELF, 0.32f);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatCount(9);
iv.startAnimation(scaleAnimation);
}
public void rotate(View view) {
// RotateAnimation rotateAnimation = new RotateAnimation(-45, 45,
// Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1);
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(10000);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.REVERSE);
iv.startAnimation(rotateAnimation);
}
public void set(View view) {
//1. 创建个动画集合
AnimationSet animationSet = new AnimationSet(false);
//2. 创建我们想要的动画对象
ScaleAnimation scaleAnimation = new ScaleAnimation(0.5f, 15f, 0.5f, 15, Animation.RELATIVE_TO_SELF, 0.45f, Animation.RELATIVE_TO_SELF, 0.32f);
scaleAnimation.setDuration(1000);
scaleAnimation.setRepeatCount(9);
//2. 创建我们想要的动画对象
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(1000);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
//3. 将动画添加到动画集合对象中
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(rotateAnimation);
//4. 执行动画
iv.startAnimation(animationSet);
}
2.xml文件实现(有利于复用)
- 平移动画
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0" // 开始的x坐标
android:fromYDelta="0" // 开始的y坐标
android:toXDelta="100" // 结束的x坐标
android:toYDelta="100" // 结束的y坐标
android:duration="500" // 动画执行时长 单位 毫秒
android:repeatCount="3"// 重复次数
android:repeatMode="reverse" // 重复模式 reverse反转restart重启
android:fillAfter="true" // 是否停留在动画结束时
>
</translate>
- 缩放动画
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.5" // 开始x方向缩放比例
android:fromYScale="0.5" // 开始y方向缩放比例
android:toXScale="1.5" // 结束x方向缩放比例
android:toYScale="1.5" // 结束y方向缩放比例
android:duration="500"
android:repeatCount="3"
android:repeatMode="reverse"
android:pivotX="50%" // x缩放中心 带p表示相对于parent父控件
android:pivotY="50%" // y缩放中心 带p表示相对于parent父控件
>
</scale>
- 旋转动画
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0" // 开始旋转角度
android:toDegrees="180" // 结束旋转角度
android:pivotX="50%"
android:pivotY="50%"
android:duration="500"
android:repeatCount="3"
android:repeatMode="reverse" >
</rotate>
- 透明度动画
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="1.0" // 开始透明度
android:toAlpha="0.3" // 结束透明度
android:repeatCount="3"
android:repeatMode="reverse"
android:duration="500" >
</alpha>
- 组合动画
<set>
...
</set>
在代码中将动画的xml转换为Animation对象
public void alpha2(View view) {
// 将动画的xml转换为Animation对象
AlphaAnimation animation = (AlphaAnimation) AnimationUtils.loadAnimation(this, R.anim.alpha_anim);
animation.setFillAfter(true);// 让动画执行完后保持执行完后的效果
iv.startAnimation(animation);
}
属性动画
1.代码实现
// 旋转动画
// 参数 >> 执行动画的控件, 属性名称, 属性值
ObjectAnimator ra = ObjectAnimator.ofFloat(iv_image, "rotation", 180f);
ra.setRepeatCount(3); // ValueAnimator.INFINITE 无限
ra.setRepeatMode(ValueAnimator.REVERSE);
ra.setDuration(500);
ra.start();
2.通过xml文件实现AnimatorInflater
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="translationX" // 属性名称
android:duration="500" // 执行时长
android:repeatCount="3" // 重复次数, infinite无限
android:repeatMode="reverse"// 重复模式 restart重启, reverse反转
android:valueType="floatType"// 值类型
android:valueFrom="-50" // 开始值
android:valueTo="100" // 结束值
>
</objectAnimator>
3.动画集合
// 动画集合
AnimatorSet set = new AnimatorSet();
// set.playTogether(ta, sa, ra, aa); // 一起播放
// set.playSequentially(ta, sa, ra, aa); // 按先后顺序播放
// 平移同时缩放, 在旋转之前, 在透明度之后
set.play(ta).with(sa).before(ra).after(aa); // 透明度 -> 平移同时缩放 -> 旋转
set.setStartDelay(1000); // 动画开始延时时间
set.start(); // 开始
,