为了吸引用户或提醒用户有的时候我们会为界面元素加入动态效果,比如在表单验证失败时为输入框添加左右抖动动画交互,当电话来话时,为电话按钮添加摇动动画效果,上下抖动某按钮吸引用户去点击等,这些交互方式通称动画交互。Android一开始就提供了两种动画方式来满足这样的交互,它们分别是逐帧动画(frame-by-frame animation)和补间动画(tweened animation)。逐帧动画的工作原理是将一个完整的动画拆分成一张张单独的图片,每一张图片称为一帧,然后再将它们连贯起来逐帧播放,而补间动画则是对View进行四种动画操作,分别是淡入淡出、缩放、平移、旋转。由于补间动画只提供了这四种动画或组合,并扩展也比较困难,所以要实现其它动画交互效果就显的很局限,幸好Android3.0给我们提供了一种全新的动画模式,属性动画(propertyanimation),它的功能非常强大,弥补了补间动画的一些缺陷,同时也可以扩展,可以满足各种各样的动画交互效果。
下面使用属性动画(property animation)动画实现的动画效果:
属性动画工作原理:在指定的时间里按指定方式改变对象(View 对象或非View 对象)的属性,从而让对象生产动画交互。
属性动画核心类:
(1) ValueAnimator类:
ValueAnimator是属性动画模式当中最核心的一个类,它最主要的作用是在动画执行的过程中计算从属性初始值过渡到终止值期间产生的过渡值。除了前面介绍的作用外,它也可以通过setDuration()设置动画播放时长,通过setRepeatCount()和setRepeatMode()方法设置动画重复次数和重复模式,通过setInterpolator()方法设置过渡值变化的规律(比如线性变化,加速变化等,这块和普通的补间动画中的插值器是一样的,下面有补充),通过addUpdateListener添加动画开始,重复,结束等事件的监听器,
通过start()方法开始计算过渡值。
ValueAnimator类对象的创建是通过调用静态工厂方法ofXXX(XXXstartValue,XXX endValue)生成的,其中的XXX代表的是ValueAnimator要计算的过渡的属性值的类型,有Float,Int,Object等。
常用插值器: LinearInterpolator(匀速)、 AccelerateInterpolator(先慢后快)、
AccelerateDecelerateInterpolator(先慢中快后慢)、
DecelerateInterpolator(先快后慢)、 CycleInterpolator(循环播放,速度为正弦曲线)、
AnticipateInterpolator(先回撤,再匀速向前)、OvershootInterpolator(超过,拉回)、
BounceInterpolator(回弹)
练习案例1:将一个值从0.0平滑过渡到1.0,时长100毫秒。
ValueAnimator anim = ValueAnimator.ofFloat(0.0f, 1.0f);
anim.setDuration(100);
anim.start();
说明:上面的案例中如果我们想要看到在100毫秒期间产生的每一个值时,需要监听动画播放事件,代码改进如下:
ValueAnimator anim = ValueAnimator.ofFloat(0.0f, 1.0f);
anim.setDuration(100);
anim.addUpdateListener(newValueAnimator.AnimatorUpdateListener() {
@Override
publicvoid onAnimationUpdate(ValueAnimator animation) {
floatcurrentValue = (float) animation.getAnimatedValue(); //获取当前计算的过渡值。这个方法会不断被回调
Log.d("TAG", "cuurent value is " +currentValue); //打印当前过渡值
}
});
anim.start();
练习案例2:将一个值从0.0平滑过渡到5.0,再过渡到-5.0,再过渡到0.0时长4000毫秒。
ValueAnimatoranim = ValueAnimator.ofFloat(0.0f, 5.0f, -5.0f, 0.0f);
anim.setDuration(4000);
anim.start();
说明:案例2说明我们可以在初始值和终止值之间插入中间值,使得我们可以按自己的想法改变某个属性值。
(2) ObjectAnimator类:
ValueAnimator类计算属性的过渡值,但没有指定要过渡哪个对象和哪个属性。实际开发中我们经常使用ObjectAnimator类,它是ValueAnimator的子类,除了具有ValueAnimator的功能,更重要的是它可以指定要动画的对象和属性。用法上和ValueAnimator差不多。需求特别说明对象的属性值一定是有get和set方法的,换句话说只要是对象的属性有get和set方法,就可以使用ObjectAnimator不断地为对象中的某个属性进行赋值(内部通过反射得到对应属性的setXXX方法来改变属性值),然后对象根据属性值的改变再来决定如何展现出来。所以我们要明白ObjectAnimator不仅仅只能操作View,非View的属性可以通过ObjectAnimator改变并赋值。
练习案例1:让一个ImageView对象的透明度属性在3秒内从1.0f透明过渡到0.0f不透明,再过渡回1.0f透明。
ImageView imageView = findViewById(R.id.iv_icon);
ObjectAnimator animator =ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.0f, 1.0f);
animator.setDuration(3000);
animator.start();
说明:ObjectAnimator的静态工厂方法ofFloat()创建ObjectAnimator的实例,第一个参数要求传入一个object对象,们这个对象是要进行动画操作的对象,这里我传入imageView。第二个参数是想要对该对象的哪个属性进行动画操作,这里我们改变的是ImageView的透明度,因此传入"alpha"属性名。后面的参数是可变长度的,想要完成什么样的动画就传入什么值,这里传入1.0f(透明),0.0f(不透明),1.0f(透明),之后调用setDuration()方法设置动画时长,然后调用start()方法启动动画。
练习案例2:在5秒内将ImageView进行5次360度的旋转。
ImageView imageView = findViewById(R.id.iv_icon);
ObjectAnimator animator =ObjectAnimator.ofFloat(imageView, "rotation", 0.0f, 360.0f);
animator.setRepeatCount(5);
animator.setDuration(5000);
animator.start();
说明:用法与案例1基本一样,用这种方式改变属性值的用法差不多都是这样的,可举一反三。需要注意是第二个参数rotation代表旋转,在ImageView中或父类中要有setRotation和getRotation,只有这样ObjectAnimator内部才会通过反射的方式调用setRotation()方法改变对应的属性值。从而最终实现旋转的动画效果。
(3) AnimatorSet类
这个类是属性动画的集合类,我们可以使用内的构建者类AnimatorSet.Builder的系列方法对多个动画组合,排序进行播放。
AnimatorSet.Builder中重要的四个方法:
after(Animator anim) 将现有动画插入到传入的动画之后执行
after(long delay) 将现有动画延迟指定毫秒后执行
before(Animator anim) 将现有动画插入到传入的动画之前执行
with(Animatoranim) 将现有动画和传入的动画同时执行
练习案例: 让一个ImageView控件在5秒之内先从屏幕外平衡进入屏幕,然后再旋转360度,同时淡入淡出。
ImageView imageView =findViewById(R.id.iv_icon);
ObjectAnimatormoveIn = ObjectAnimator.ofFloat(imageView, "translationX", -480.0f, 0.0f);
ObjectAnimatorrotate = ObjectAnimator.ofFloat(imageView, "rotation", 0.0f, 360.0f);
ObjectAnimatorfadeInOut = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.0f, 1.0f);
AnimatorSetanimSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();
(4)PropertyValuesHolder类
PropertyValuesHolder类的作用是保存对象属性的信息以及在动画播放过程中生成的属性的过渡值。通过PropertyValuesHolder类的静态工厂方法ofKeyframe()来构建PropertyValuesHolder的实例对象,ofKeyframe()方法接收一个属性名以和多个Keyframe类对象作为参数。当我们想改变多个属性的时候使用PropertyValuesHolder非常有用和方便。
(5)Keyframe类
Keyframe类是关键帧类,与PropertyValuesHolder配合使用,是一个时间/值对,作用是定义动画播放到某个时刻时(时间用百分比来表示,范围是0到1,代表0%到100%)某属性值是多少。获取Keyframe类对象的方式是调用onXXX()方法,XXX表示属性值数据类型,常用的有ofInt,ofFloat,ofObject,比如Keyframe.ofInt(0.3f, Color.RED)定义了当动画播放到总时长的30%时,颜色属性的值是Color.RED(红色)。
练习案例1:电话图标上下抖动动画。
效果图:
上下抖动原理:
对电话图标的ImageView控件的x轴和y轴进行0.8倍到1.2倍的缩放动画,同时对ImageView进行一定角度的上下旋转。
核心代码:
/**
* 执行上下加旋转抖动动画
* @paramview
*/
private voidshakeImageView(View view) {
PropertyValuesHolder animScaleX =PropertyValuesHolder.ofKeyframe(View.SCALE_X,
Keyframe.ofFloat(0.0f, 1.0f),
Keyframe.ofFloat(0.1f, 0.8f),
Keyframe.ofFloat(0.2f, 0.8f),
Keyframe.ofFloat(0.3f,1.2f),
Keyframe.ofFloat(0.4f, 1.2f),
Keyframe.ofFloat(0.5f, 1.2f),
Keyframe.ofFloat(0.6f, 1.2f),
Keyframe.ofFloat(0.7f, 1.2f),
Keyframe.ofFloat(0.8f, 1.2f),
Keyframe.ofFloat(0.9f, 1.2f),
Keyframe.ofFloat(1.0f, 1.0f)
);
// 生成对ImageView的x轴进行0.8倍到1.2倍的缩放动画对应的PropertyValuesHolder对象
PropertyValuesHolder animScaleY =PropertyValuesHolder.ofKeyframe(View.SCALE_Y,
Keyframe.ofFloat(0.0f, 1.0f),
Keyframe.ofFloat(0.1f, 0.8f),
Keyframe.ofFloat(0.2f, 0.8f),
Keyframe.ofFloat(0.3f, 1.2f),
Keyframe.ofFloat(0.4f, 1.2f),
Keyframe.ofFloat(0.5f, 1.2f),
Keyframe.ofFloat(0.6f, 1.2f),
Keyframe.ofFloat(0.7f, 1.2f),
Keyframe.ofFloat(0.8f, 1.2f),
Keyframe.ofFloat(0.9f, 1.2f),
Keyframe.ofFloat(1.0f, 1.0f)
);
// 生成对ImageView进行一定角度的上下旋转动画的PropertyValuesHolder对象
PropertyValuesHolder animRotate =PropertyValuesHolder.ofKeyframe(View.ROTATION,
Keyframe.ofFloat(0.0f,0.0f),
Keyframe.ofFloat(0.1f, -9.0f),
Keyframe.ofFloat(0.2f, -9.0f),
Keyframe.ofFloat(0.3f, 9.0f),
Keyframe.ofFloat(0.4f, -9.0f ),
Keyframe.ofFloat(0.5f, 9.0f),
Keyframe.ofFloat(0.6f, -9.0f),
Keyframe.ofFloat(0.7f, 9.0f),
Keyframe.ofFloat(0.8f, -9.0f),
Keyframe.ofFloat(0.9f, 9.0f),
Keyframe.ofFloat(1.0f, 0.0f)
);
// 调用ObjectAnimator类的ofPropertyValuesHolder方法,指定对象与多个动画对应的PropertyValuesHolder,
// 同时设置动画执行时长为1000毫秒
ObjectAnimator objectAnimator =ObjectAnimator.ofPropertyValuesHolder(view, animScaleX, animScaleY, animRotate). setDuration(1000);
objectAnimator.setRepeatCount(50);
objectAnimator.setRepeatMode(ObjectAnimator.RESTART);
objectAnimator.start();
}
练习案例2:当点击登录按钮时检查用户名输入框和密码输入框的内容不等于“kedi”和”123456“就左右抖动,
提示用户输入错误。
效果图:
左右抖动原理:
对EditText控件进行x轴的平移属性动画。
核心代码:
/**
* 执行左右抖动动画的方法
*
* @paramview
*/
private voidshakeEditText(View view) {
PropertyValuesHolder animTranslateX =PropertyValuesHolder.ofKeyframe(View.TRANSLATION_X,
Keyframe.ofFloat(0.0f, 0.0f),
Keyframe.ofFloat(0.10f, -20.0f),
Keyframe.ofFloat(0.26f, 20.0f),
Keyframe.ofFloat(0.42f, -20.0f),
Keyframe.ofFloat(0.58f, 20.0f),
Keyframe.ofFloat(0.74f, -20.0f),
Keyframe.ofFloat(0.90f,20.0f),
Keyframe.ofFloat(1.0f, 0.0f)
);
ObjectAnimator.ofPropertyValuesHolder(view, animTranslateX).setDuration(500).start();
}