在进行转场的时候经常需要设置动画,这里提供了animator相关的类
一、关于view的动画
正常用到的有RotateAnimation、TranslateAnimation、ScaleAnimation、AlphaAnimation
也可以多个动画的组合AnimationSet
AnimationSet as = new AnimationSet(true);
as.setDuration(1000);
AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(1000);
as.addAnimation(aa);
TranslateAnimation ta = new TranslateAnimation(0, 100, 0, 200);
ta.setDuration(1000);
as.addAnimation(ta);
view.startAnimation(as);
如上AnimationSet设置的时间为1000毫秒,然后将AlphaAnimation和TranslateAnimation创建的对象均加到AnimationSet成为组合的方式,最终view的startAnimation(as); 注意最后一定要start,否则不会做效果
使用view操作该AnimationSet的时候view向右下角移动,但是在原来的位置点击依旧会有点击的响应。
二、ObjectAnimator
使用ObjectAnimator则不会出现一中的view其他地方移动但是在原来的位置点击依旧响应的情况
通过ObjectAnimator的静态工厂方法可以创建出ObjectAnimator,比如:ObjectAnimator oaa = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f);
工厂方法的第一个参数是要操纵的view,第二个是要操纵的属性,第三个是一个可变的数组参数对应的是属性的变化过程;
如上的ooa的变化过程假设imageView开始的alpha是1,则上面的oaa让imageView从alpha等于1到0.5的一个变化的过程
这里需要注意的是第二个属性必须有对应的get和set方法否则ObjectAnimator无法起效,如果没有对应的get和set方法则需要自己封装一个对应的get和set方法
如下是常见的变换属性
private void AnimatorsOut() {
ObjectAnimator oaa = ObjectAnimator.ofFloat(mImageViews.get(0), "alpha", 0.5f);
ObjectAnimator oab = ObjectAnimator.ofFloat(mImageViews.get(1), "translationX", 200);
ObjectAnimator oac = ObjectAnimator.ofFloat(mImageViews.get(2), "translationX", -200);
ObjectAnimator oad = ObjectAnimator.ofFloat(mImageViews.get(3), "translationY", 200);
ObjectAnimator oae = ObjectAnimator.ofFloat(mImageViews.get(4), "translationY", -200);
AnimatorSet as = new AnimatorSet();
as.playTogether(oaa, oab, oac, oad, oae); // 这里使用组合的方式,即oaa到oae是一起做动画效果,如果调用as.playSequentially 则是按顺序做效果
as.setInterpolator(new BounceInterpolator()); // 这里设置了Interpolators(插值器),插值器会让孔吉娜产生不同的动画特效,比如这个BounceInterpolator是反弹,还有其他的特效LinearInterpolator 等
as.start(); // 设置完成之后,这里调用start才能开始做效果
}
如上是一个简单的ObjectAnimator的做特效的过程,AnimatorSet用来组装多个特效
三、ValueAnimator
使用方式跟ObjectAnimator几乎是一样的,只是它没有ObjectAnimator的第一个参数
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
// 增加对应的值变更监听
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
((TextView)view).setText("$ " + (Integer)animation.getAnimatedValue()); // animation.getAnimatedValue() 返回的是object对象,需要强转为对应的类型
}
});
valueAnimator.setDuration(3000); // 设置做动画时间为3秒,动画使用3秒的时间从0到100按顺序调用onAnimationUpdate均匀更新调用,如果调用过程中有卡住的情况,animation.getAnimatedValue()回调的某些值可能会跳过
valueAnimator.start();
如上所示是ValueAnimator的一个简单调用
四、ObjectAnimator和ValueAnimator的监听
安卓提供了一个完整的动画具有Start, Repeat, End, Cancel
animator.addListener(new Animator.AnimatorListener() { 。。。。})
AnimatorListener的接口如下所示:
/**
* <p>An animation listener receives notifications from an animation.
* Notifications indicate animation related events, such as the end or the
* repetition of the animation.</p>
*/
public static interface AnimatorListener {
/**
* <p>Notifies the start of the animation as well as the animation's overall play direction.
* This method's default behavior is to call {@link #onAnimationStart(Animator)}. This
* method can be overridden, though not required, to get the additional play direction info
* when an animation starts. Skipping calling super when overriding this method results in
* {@link #onAnimationStart(Animator)} not getting called.
*
* @param animation The started animation.
* @param isReverse Whether the animation is playing in reverse.
*/
default void onAnimationStart(Animator animation, boolean isReverse) {
onAnimationStart(animation);
}
/**
* <p>Notifies the end of the animation. This callback is not invoked
* for animations with repeat count set to INFINITE.</p>
*
* <p>This method's default behavior is to call {@link #onAnimationEnd(Animator)}. This
* method can be overridden, though not required, to get the additional play direction info
* when an animation ends. Skipping calling super when overriding this method results in
* {@link #onAnimationEnd(Animator)} not getting called.
*
* @param animation The animation which reached its end.
* @param isReverse Whether the animation is playing in reverse.
*/
default void onAnimationEnd(Animator animation, boolean isReverse) {
onAnimationEnd(animation);
}
/**
* <p>Notifies the start of the animation.</p>
*
* @param animation The started animation.
*/
void onAnimationStart(Animator animation);
/**
* <p>Notifies the end of the animation. This callback is not invoked
* for animations with repeat count set to INFINITE.</p>
*
* @param animation The animation which reached its end.
*/
void onAnimationEnd(Animator animation);
/**
* <p>Notifies the cancellation of the animation. This callback is not invoked
* for animations with repeat count set to INFINITE.</p>
*
* @param animation The animation which was canceled.
*/
void onAnimationCancel(Animator animation);
/**
* <p>Notifies the repetition of the animation.</p>
*
* @param animation The animation which was repeated.
*/
void onAnimationRepeat(Animator animation);
}
View Code
但是我们正常只会想要其中的一两个借口,那么我们可以使用AnimatorListenerAdapter这个类,如下的调用
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view.setVisibility(View.GONE);
}
});
这里我只需要end这个借口,则只需要实现该接口即可,无需实现其他的接口
5、自定义动画
我们上面介绍的ObjectAnimator和ValueAnimator都是实现Animator接口
我们如果想要实现自定义动画则可以通过实现Animator接口
如下是一个简单的实现过程,调用applyTransformation实现对应的动画逻辑;如果需要初始化,则可以调用initialize 进行一些需要的初始化
public class CustomAnim extends Animation {
private int mCenterHeight;
private int mCenterWidth;
private Camera mCamera = new Camera();
private float mRotateY = 0;
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
setDuration(2000);
setFillAfter(true);
setInterpolator(new AccelerateInterpolator());
mCenterHeight = height / 2;
mCenterWidth = width / 2;
}
public void setRotateY(float rotateY) {
mRotateY = rotateY;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
Matrix matrix = t.getMatrix(); // 该矩阵则是当前interpolatedTime动画要显示的效果
mCamera.save();
mCamera.rotateY(mRotateY * interpolatedTime);
mCamera.getMatrix(matrix);
mCamera.restore();
matrix.preTranslate(mCenterWidth, mCenterHeight);
matrix.postTranslate(-mCenterWidth, -mCenterHeight);
}
}