属性动画Property Animation
由于Tween Animation(补间动画)只能实现简单的四种的动画(alpha、scale、rotate、translate),要想实现比较复杂的动画就难以满足需求,而且补间动画只是改变了View对象绘制的位置,而没有改变View对象本身,比如View形状的变换,如大小的缩放,透明度的改变,位置的改变,其实本身并没有改变,举个例子就好比孙悟空灵魂出窍一样,虽然已经上天入地,其实肉体还在那里一动不动,我们开发过程中的经常遇见的就是translate之后事件还在原地。如果要实现既要有动画效果又要使得View本身得到真正改变,那就要借助属性动画了,这也是属性动画引入的原因。它能够更加灵活的实现各种效果,不仅限于类似补间动画实现的哪几种效果。
ObjectAnimator:
ValueAnimator的一个子类,允许你设置一个目标对象和对象的属性进行动画。当这个类计算好一个动画的新值后,相应的会更新其属性。大多数时候你都会想用ObjectAnimator,因为它使得动画值到目标对象的处理更简单了。
以实现一个View透明渐变效果为例进行说明
对于java代码实现,ObjectAnimator提供了以下几个方法:ofFloat(),ofInt(),ofObject(),ofArgb(),ofPropertyValuesHolder()这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。
//透明渐变效果
public void initXMLAnimAlpha() {
Animator anim = AnimatorInflater
.loadAnimator(context, R.animator.animator_alpha);
anim.setTarget(imageView);
anim.start();
}
public void initJavaAnimAlpha() {
ObjectAnimator alphaAnimation = ObjectAnimator
.ofFloat(imageView, "alpha", 0f, 1f);
alphaAnimation.setDuration(500);
alphaAnimation.setRepeatCount(0);
alphaAnimation.setRepeatMode(ValueAnimator.REVERSE);
alphaAnimation.setStartDelay(200);
alphaAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
alphaAnimation.start();
}
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:propertyName="alpha"
android:repeatCount="1"
android:repeatMode="reverse"
android:startOffset="200"
android:valueFrom="0.0"
android:valueTo="1.0"
android:valueType="floatType"/>
<!--
duration 表示动画执行的时间
propertyName 表示修改的物件的哪个属性值,这里是透明度
repeatCount 动画重复的计数,动画将会执行该值+1次
repeatMode 动画重复的模式,reverse为反向,当第偶次执行时,
动画方向会相反。restart为重新执行,方向不变
startOffset, 动画多次执行的间隔时间,如果只执行一次,
执行前会暂停这段时间,单位毫秒
valueFrom 表示从哪个状态值开始动画
valueTo 表示到哪个状态值结束动画
valueType 类型估值,主要用于设置动画操作属性的值
interpol
缩放动画:
public void initXMLAnimScale() {
Animator anim = AnimatorInflater
.loadAnimator(context, R.animator.animator_scaleX);
anim.setTarget(imageView);
anim.start();
}
public void initJavaAnimScale() {
ObjectAnimator scaleXAnimator = ObjectAnimator
.ofFloat(imageView, "scaleX", 1f, 1.5f);
scaleXAnimator.setDuration(500);
scaleXAnimator.setRepeatCount(1);
scaleXAnimator.setRepeatMode(ValueAnimator.REVERSE);
scaleXAnimator.start();
}
R.animator.animator_scaleX
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:propertyName="scaleX"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="1.0"
android:valueTo="1.5"
android:valueType="floatType"/>
旋转动画:
public void initXMLAnimRotation() {
Animator anim = AnimatorInflater
.loadAnimator(context, R.animator.animator_rotation);
anim.setTarget(imageView);
anim.start();
}
public void initJavaAnimRotation() {
ObjectAnimator objectAnimator = ObjectAnimator
.ofFloat(imageView, "rotation", 0f, 360f);
objectAnimator.setDuration(500);
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.start();
}
R.animator.animator_rotation
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:interpolator=
"@android:anim/accelerate_decelerate_interpolator"
android:propertyName="rotation"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType"/>
平移动画:
public void initXMLAnimTranslationX() {
Animator anim = AnimatorInflater
.loadAnimator(context, R.animator.animator_translationX);
anim.setTarget(imageView);
anim.start();
}
public void initJavaAnimTranslationX() {
ObjectAnimator objectAnimator = ObjectAnimator
.ofFloat(imageView, "translationX", 0f, 100f);
objectAnimator.setDuration(500);
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.start();
}
R.animator.animator_translationX
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:propertyName="translationX"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="0"
android:valueTo="100"
android:valueType="floatType"/>
如何实现一个组合动画
方式一:使用AnimatorSet
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:duration="500"
android:propertyName="scaleX"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="1.0"
android:valueTo="1.5"
android:valueType="floatType"/>
<objectAnimator
android:duration="500"
android:propertyName="scaleY"
android:repeatCount="1"
android:repeatMode="reverse"
android:valueFrom="1.0"
android:valueTo="1.5"
android:valueType="floatType"/>
</set>
//如何实现一个组合动画
public void initXMLAnimSet() {
Animator anim = AnimatorInflater
.loadAnimator(context, R.animator.animator_set);
anim.setTarget(imageView);
anim.start();
}
public void initJavaAnimSet() {
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator scaleXAnimator = ObjectAnimator
.ofFloat(imageView, "scaleX", 1f, 1.5f);
scaleXAnimator.setDuration(500);
scaleXAnimator.setRepeatCount(1);
scaleXAnimator.setRepeatMode(ValueAnimator.REVERSE);
scaleXAnimator.start();
ObjectAnimator scaleYAnimator = ObjectAnimator
.ofFloat(imageView, "scaleY", 1f, 1.5f);
scaleYAnimator.setDuration(500);
scaleYAnimator.setRepeatCount(1);
scaleYAnimator.setRepeatMode(ValueAnimator.REVERSE);
animatorSet.playTogether(scaleXAnimator, scaleYAnimator);
animatorSet.start();
}
上述代码通过playTogether函数实现两个动画同时执行,如果不想同时执行,也可以调用play函数返回AnimatorSet.Builder实例,AnimatorSet.Builder提供了如下几个函数用于实现动画组合:
1,after(Animator anim) 将现有动画插入到传入的动画之后执行
2,after(long delay) 将现有动画延迟指定毫秒后执行
3,before(Animator anim) 将现有动画插入到传入的动画之前执行
4,with(Animator anim) 将现有动画和传入的动画同时执行
也可以调用playSequentially函数实现分布执行动画。
方式二:使用PropertyValuesHolder
/*
通过这种方式只能实现同时执行的动画组合相比AnimatorSet就没那么丰富了,
PropertyValuesHolder 提供的函数方法有如下几种:
ofInt()、ofFloat()、ofObject()、ofKeyframe()。
*/
public void initPropertyValuesHolder() {
PropertyValuesHolder scaleXValuesHolder = PropertyValuesHolder
.ofFloat("scaleX", 1.0f, 1.5f);
PropertyValuesHolder scaleYValuesHolder = PropertyValuesHolder
.ofFloat("scaleY", 1.0f, 1.5f);
ObjectAnimator objectAnimator = ObjectAnimator
.ofPropertyValuesHolder(imageView,
scaleXValuesHolder, scaleYValuesHolder);
objectAnimator.setDuration(500);
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.start();
}
方式三:使用ViewPropertyAnimator
/*
多属性动画,作用于View,能够实现的动画相对单一,只能实现比如缩放,透明度改变,
平移、旋转等,具体函数名字:平移 translationX,translationY, X,Y,
缩放 scaleX,scaleY, 旋转 rotationX, rotationY,透明度 alpha
*/
public void initViewPropertyAnimator() {
ViewPropertyAnimator viewPropertyAnimator = imageView.animate();
viewPropertyAnimator.scaleXBy(1.0f).scaleX(1.5f)
.scaleYBy(1.0f).scaleY(1.5f).setDuration(500).start();
}
设置动画监听器
addListener
有时候我们可能要在某一个动画执行之前或者动画结束之后进行一些其他的操作,这个时候就要借助动画监听器了。
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//TODO 动画开始前的操作
}
@Override
public void onAnimationEnd(Animator animation) {
//TODO 动画结束的操作
}
@Override
public void onAnimationCancel(Animator animation) {
//TODO 动画取消的操作
}
@Override
public void onAnimationRepeat(Animator animation) {
//TODO 动画重复的操作
}
});
AnimatorUpdateListener
如果我们需要简单动画执行过程中的变化可以使用AnimatorUpdateListener
objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//可以根据自己的需要来获取动画更新值。
Log.e("AnimatorUpdateListener", "the animation value is " + value);
}
});