Android动画可以分为3类:View动画,帧动画,属性动画
1.View动画
可以通过XML来创建,也可以通过代码来创建
1.1通过XML创建
在res/anim下创建filename.xml文件,语法如下所示
<?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>
View动画不止能够写单个的动画,也可以使用动画集合.<set>代表动画集合(对应于AnimationSet).
1.1.1:interpolator:差值器,可以影响动画的速度。
1.1.2:shareInterpolator是否共享一个差值器,如果集合不指定差值器,子动画就需要指定差值器或者使用默认的差值器。
1.1.3:scale的轴点:pivotX和pivotY
轴点与在中间和在左右2侧的效果是不同的。
1.1.4:duration
1.1.5:fillAfter动画结束后是否停留在结束的位置。
具体例子
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="false"
>
<translate
android:duration="100"
android:fromXDelta="0"
android:toXDelta="100"
android:fromYDelta="0"
android:toYDelta="100"
android:interpolator="@android:anim/linear_interpolator"/>
<rotate
android:duration="400"
android:fromDegrees="0"
android:toDegrees="90"
/>
</set>
使用方式
Animation animation = AnimationUtils.loadAnimation(AnimationActivity.this, R.anim.filename);
mButton.startAnimation(animation);
1.2通过代码创建
略
1.3View动画使用场景
A.ViewGroup子View的出场效果
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:interpolator="@android:anim/accelerate_interpolator"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"></alpha>
<translate
android:fromYDelta="500"
android:toYDelta="0"></translate>
</set>
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/anim_item">
</layoutAnimation>
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
v.setLayoutAnimation(controller);
//或者直接在XMl中使用
<ListView
android:id="@+id/list"
android:cacheColorHint="#00000000"
android:divider="#dddbdb"
android:dividerHeight="1.0px"
android:background="#fff4f7f9"
android:layoutAnimation="@anim/anim_layout"
android:listSelector="@android:color/transparent"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ListView>
delay是延时周期(如果周期是300ms延时就是0.5*300=150,第一个是150ms后开始动画,第二个是延时300ms后开始变化,以此类推)
B.Activity之间的切换效果
主要用到了overridePendingTransition这个方法,但是这个方法需要在startActivity之前和finish之后调用才会有效
2.帧动画
3.属性动画
属性动画可以对任意对象的属性进行动画而不仅仅是View,在一定的时间间隔内完对象从一个属性值到另一个属性值得改变,但是属性动画是从Api11才开始有的.
常用的几个类是:ValueAnimator.ObjectAnimator和AnimatorSet其中ObjectAnimator继承自ValueAnimator,AnimatorSet是一个动画集合.可以定义一组动画。
通过代码实现
单个属性与属性集合
private void startObjectAnimator(View object) {
ObjectAnimator.ofFloat(object, "translationY", -object.getHeight()).start();
}
private void startColorProperty(View view) {
ValueAnimator colorAnim = ObjectAnimator.ofInt(view, "backgroundColor", 0xFFFF8080,
0xFF8080FF);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();
}
private void startSetProperty(View view) {
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(view, "rotationX", 0, 360),
ObjectAnimator.ofFloat(view, "rotationY", 0, 360),
ObjectAnimator.ofFloat(view, "rotation", 0, -90),
ObjectAnimator.ofFloat(view, "translationX", 0, 90),
ObjectAnimator.ofFloat(view, "translationY", 0, 90),
ObjectAnimator.ofFloat(view, "scaleX", 1, 1.5f),
ObjectAnimator.ofFloat(view, "scaleY", 0, 0.5f),
ObjectAnimator.ofFloat(view, "alpha", 0, 0.25f, 1)
);
set.setDuration(5 * 1000).start();
}
通过XML定义,属性动画定义在res/animator/下
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:propertyName="x"
android:duration="300"
android:valueTo="200"
android:valueType="intType"></objectAnimator>
<objectAnimator
android:propertyName="y"
android:duration="300"
android:valueTo="300"
android:valueType="intType"></objectAnimator>
</set>
加载上面的动画给View
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.property_animator);
animatorSet.setTarget(view);
animatorSet.start();
理解差值器和估值器
TimeInterpolator翻译成时间差值器,他的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比.
TypeEvaluator的中文翻译是类型估值算法,就是估值器,它的作用是根据当前属性改变的百分比来计算改变后的属性值.
如果需要对其他类型做动画(比如非int,float,color)这时候就需要自定义类型估值算法.
属性动画注意事项:
属性动画要求对象的属性有set和get(可选)方法.
属性动画的监听器
属性动画对于监听动画的过程提供了两个接口AnimatorUpdateListener和AnimatorListener
public static interface AnimatorListener {
default void onAnimationStart(Animator animation, boolean isReverse) {
onAnimationStart(animation);
}
default void onAnimationEnd(Animator animation, boolean isReverse) {
onAnimationEnd(animation);
}
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
监听了动画的开始,结束,取消和重复,而且系统提供了AnimatorListenerAdapter这个类,方便我们去继承上面几个方法任意的组合.
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
监听动画的整个过程,动画是由许多帧来组成的,每播放一帧,onAnimatorUpdate就会调用一次.
对任意属性做动画
属性动画是根据外界传递给该属性的初始值和最终值,通过不断的调用set方法,每次传递给set方法的值都不一样,但是越来越接近最终值.这样,对object的abc属性做动画,需要动画生效就需要满足2个条件:
(1):需要提供setAbc()方法,如果做动画的时候没有传递初始值,那么还需要提供getAbc方法,因为系统要去取abc属性的初始值(如果这条不满足,程序直接 Crash).
(2):object的setAbc()方法对属性abc所做的改变必须通过某种方法反映出来,比如会带来UI的改变之类的(如果这条不满足,动画无效但是不会Crash).
对于没有提供get和set方法的属性动画,官方提供了3种解决办法.
对于属性动画的3种解决办法:
1.给你的对象加上get和set方法.
2.采用一个类来包装原始对象,间接为其提供get和set方法.
3.采用ValueAnimator,监听动画过程,自己实现属性的改变.
1.给你的对象加上get和set方法
这种通常对于SDK中的View,是没有权限的.
2.用一个类来包装原始对象,间接为其提供get和set方法.
private static class ViewWrapper {
private View mTarget;
public ViewWrapper(View target) {
this.mTarget = target;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
}
//使用上面的包装类
ViewWrapper wrapper = new ViewWrapper(view);
ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(5000).start();
本来想改变Button的width,结果setWidth改变的与我们想要的不是同一个东西,将Button包裹为target,通过改变其LayourParams的width来达到动画的效果.
3.采用ValueAnimator,监听动画过程,自己实现属性的改变.
ValueAnimator本身不作用于任何对象,也就是说直接使用它没有任何效果,可以使用它对一个值做动画,我们对一个值做动画,然后监听它的动画过程,在过程中修改我们动画的属性值.
private void performAnimator(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//估值对象,方便估值的时候使用
private IntEvaluator mEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取当前的进度
int currentValue = (int) animation.getAnimatedValue();
float fraction = animation.getAnimatedFraction();
//重新计算width,然后设置给LayoutParams最后重新绘制
target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
以上就是Android动画的大概内容,其余如属性动画的工作原理,没有讲述.
可能出现的问题:
1.View动画是对View的影像做动画,有时候会出现动画完成了但是View无法隐藏的现象,就是setVisibility(View.GONE)失效了,这时候只要调用view.clearAnimation()清除View动画就可以解决.
2.在进行动画的过程中,尽量使用dp,使用px会导致在不同的设备上有不同的效果.