Android -- NineOldAndroids animation 封装

1.概述

  说起空间动态、微博的点赞效果,网上也是很泛滥,各种实现与效果一大堆。而详细实现的部分,讲述的也是参差不齐,另一方面估计也有很多大侠也不屑一顾,觉得完全没必要单独开篇来写和讲解吧。毕竟,也就是两个view和一些简单的动画效果罢了。 
  单若是只讲这些,我自然也是不愿花这番功夫的。虽然自己很菜,可也不甘于太菜。所以偶尔看到些好东西,可以延伸学写下,我还是很情愿拿出来用用,顺带秀一秀逼格什么的。 
  不扯太多,先说说今天实现点赞效果用到的自以为不错的两个点:

  • AndroidViewAnimations 基于nineoldandroids封装的android动画简易类库。究竟有多简单呢,就像这样

    AnimHelper.with(new PulseAnimator()).duration(1000).playOn(imageView); 
    作用: 在imageView上使用PulseAnimator这个动画效果,播放一秒。

1.1 动画库的封装和快速框架

  提到动画,Android本身自带的动画类Animation已经做到支持3.0及以上了,虽然也做了很好的封装,但是做起复杂动画来还是不够像上边那样简洁。在关于动画兼容方面,github上的大牛Jake Wharton又做了一套动画开源库NineOldAndroids,效果很好而且支持3.0级以前的版本,确实很值得称赞。而在此基础上,有很多高手又做了二次封装,实现了复杂动画,同时保证方便简洁,而且通用性和扩展性更高。我们这里的动画使用的就是这样一个简单的封装。 
  比如,要在XXView上时用XXAnimator这样的动画,持续Duration秒。就这么一行代码:

AnimHelper.with(new SlideOutUpAnimator()).duration(1000).playOn(textView);

  来看一下基于NineOldAndroids的ViewAnimations具体实现。

1. 首先定义一个基本动画效果类BaseViewAnimator

  这个BaseViewAnimator动画类使用一个动画集合AnimatorSet,包装成单个动画类似的用法,并定义了一个abstract方法prepare():

package com.xiaobai.mizar.utils.anim;

import android.view.View;
import android.view.animation.Interpolator;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.view.ViewHelper;

/**
 * Author: walid
 * Date : 2016/4/16 11:30
 */
public abstract class BaseViewAnimator {

	public static final long DURATION = 1000;

	private AnimatorSet animatorSet;
	private long mDuration = DURATION;

	{
		animatorSet = new AnimatorSet();
	}

	protected abstract void prepare(View target);

	public BaseViewAnimator setTarget(View target) {
		reset(target);
		prepare(target);
		return this;
	}

	public void animate() {
		start();
	}

	/**
	 * reset the view to default status
	 *
	 * @param target
	 */
	public void reset(View target) {
		ViewHelper.setAlpha(target, 1);
		ViewHelper.setScaleX(target, 1);
		ViewHelper.setScaleY(target, 1);
		ViewHelper.setTranslationX(target, 0);
		ViewHelper.setTranslationY(target, 0);
		ViewHelper.setRotation(target, 0);
		ViewHelper.setRotationY(target, 0);
		ViewHelper.setRotationX(target, 0);
		ViewHelper.setPivotX(target, target.getMeasuredWidth() / 2.0f);
		ViewHelper.setPivotY(target, target.getMeasuredHeight() / 2.0f);
	}

	/**
	 * start to animate
	 */
	public void start() {
		animatorSet.setDuration(mDuration);
		animatorSet.start();
	}

	public BaseViewAnimator setDuration(long duration) {
		mDuration = duration;
		return this;
	}

	public BaseViewAnimator setStartDelay(long delay) {
		getAnimatorAgent().setStartDelay(delay);
		return this;
	}

	public long getStartDelay() {
		return animatorSet.getStartDelay();
	}

	public BaseViewAnimator addAnimatorListener(Animator.AnimatorListener l) {
		animatorSet.addListener(l);
		return this;
	}

	public void cancel() {
		animatorSet.cancel();
	}

	public boolean isRunning() {
		return animatorSet.isRunning();
	}

	public boolean isStarted() {
		return animatorSet.isStarted();
	}

	public void removeAnimatorListener(Animator.AnimatorListener l) {
		animatorSet.removeListener(l);
	}

	public void removeAllListener() {
		animatorSet.removeAllListeners();
	}

	public BaseViewAnimator setInterpolator(Interpolator interpolator) {
		animatorSet.setInterpolator(interpolator);
		return this;
	}

	public long getDuration() {
		return mDuration;
	}

	public AnimatorSet getAnimatorAgent() {
		return animatorSet;
	}

}

  复杂动画效果基类BaseViewAnimator使用一个AnimatorSet集合来添加各种动画 ,并绑定到目标targetView ,使用 prepare(View target) 的abstract方法供其子类实现具体的动画效果。 

2. 其次基于这个类实现我们的各种动画效果XXAnimator

 当我们要实现具体的动画效果时,可以直接继承这个类并实现prepaer方法。比如这里定义的上划消失SlideOutUpAnimator 和放大回缩动画PulseAnimator

package com.xiaobai.mizar.utils.anim;

import android.view.View;
import com.nineoldandroids.animation.ObjectAnimator;

/**
 * Author: walid
 * Date : 2016/4/16 11:33
 * 放大效果
 */
public class PulseAnimator extends BaseViewAnimator {
	@Override
	public void prepare(View target) {
		getAnimatorAgent().playTogether(
				ObjectAnimator.ofFloat(target, "scaleY", 1, 1.3f, 1),
				ObjectAnimator.ofFloat(target, "scaleX", 1, 1.3f, 1)
		);
	}
}

package com.xiaobai.mizar.utils.anim;

import android.view.View;
import android.view.ViewGroup;
import com.nineoldandroids.animation.ObjectAnimator;

/**
 * Author: walid
 * Date : 2016/4/16 11:33
 * 上划消失(飘+1)
 */
public class SlideOutUpAnimator extends BaseViewAnimator {
	@Override
	public void prepare(View target) {
		ViewGroup parent = (ViewGroup) target.getParent();
		getAnimatorAgent().playTogether(
				ObjectAnimator.ofFloat(target, "alpha", 1, 0),
				ObjectAnimator.ofFloat(target, "translationY", 0, -parent.getHeight() / 2)
		);
	}
}

 上边两种动画效果就是对BaseViewAnimator的两种实现,动画本身使用的库是NineOldAndroids。

3. 最后封装一个动画管理工具类AnimHelper供外部使用

 首先定义了一个静态类,使用helper来实例化这个静态类,并设置各个参数选项。

package com.xiaobai.mizar.utils.anim;

import android.view.View;
import android.view.animation.Interpolator;
import com.nineoldandroids.animation.Animator;

import java.util.ArrayList;
import java.util.List;

/**
 * Author: walid
 * Date : 2016/4/16 11:32
 */
public class AnimHelper {

	private static final long DURATION = BaseViewAnimator.DURATION;
	private static final long NO_DELAY = 0;

	/**
	 * 实例化得到AnimationComposer的唯一接口
	 */
	public static AnimationComposer with(BaseViewAnimator animator) {
		return new AnimationComposer(animator);
	}

	/**
	 * 定义与动画效果相关联的各种参数,
	 * 使用这种方法可以保证对象的构建和他的表示相互隔离开来
	 */
	public static final class AnimationComposer {

		private List<Animator.AnimatorListener> callbacks = new ArrayList<>();
		private BaseViewAnimator animator;
		private long duration = DURATION;
		private long delay = NO_DELAY;
		private Interpolator interpolator;
		private View target;

		private AnimationComposer(BaseViewAnimator animator) {
			this.animator = animator;
		}

		public AnimationComposer duration(long duration) {
			this.duration = duration;
			return this;
		}

		public AnimationComposer delay(long delay) {
			this.delay = delay;
			return this;
		}

		public AnimationComposer interpolate(Interpolator interpolator) {
			this.interpolator = interpolator;
			return this;
		}


		public AnimationComposer withListener(Animator.AnimatorListener listener) {
			callbacks.add(listener);
			return this;
		}

		public AnimManager playOn(View target) {
			this.target = target;
			return new AnimManager(play(), this.target);
		}

		private BaseViewAnimator play() {
			animator.setTarget(target);
			animator.setDuration(duration)
			        .setInterpolator(interpolator)
			        .setStartDelay(delay);

			if (callbacks.size() > 0) {
				for (Animator.AnimatorListener callback : callbacks) {
					animator.addAnimatorListener(callback);
				}
			}

			animator.animate();
			return animator;
		}
	}

	/**
	 * 动画管理类
	 */
	public static final class AnimManager {

		private BaseViewAnimator animator;
		private View target;

		private AnimManager(BaseViewAnimator animator, View target) {
			this.target = target;
			this.animator = animator;
		}

		public boolean isStarted() {
			return animator.isStarted();
		}

		public boolean isRunning() {
			return animator.isRunning();
		}

		public void stop(boolean reset) {
			animator.cancel();
			if (reset) {
				animator.reset(target);
			}
		}
	}


}

你可能感兴趣的:(Android -- NineOldAndroids animation 封装)