说起空间动态、微博的点赞效果,网上也是很泛滥,各种实现与效果一大堆。而详细实现的部分,讲述的也是参差不齐,另一方面估计也有很多大侠也不屑一顾,觉得完全没必要单独开篇来写和讲解吧。毕竟,也就是两个view和一些简单的动画效果罢了。
单若是只讲这些,我自然也是不愿花这番功夫的。虽然自己很菜,可也不甘于太菜。所以偶尔看到些好东西,可以延伸学写下,我还是很情愿拿出来用用,顺带秀一秀逼格什么的。
不扯太多,先说说今天实现点赞效果用到的自以为不错的两个点:
AndroidViewAnimations 基于nineoldandroids封装的android动画简易类库。究竟有多简单呢,就像这样
AnimHelper.with(new PulseAnimator()).duration(1000).playOn(imageView);
作用: 在imageView上使用PulseAnimator这个动画效果,播放一秒。
提到动画,Android本身自带的动画类Animation已经做到支持3.0及以上了,虽然也做了很好的封装,但是做起复杂动画来还是不够像上边那样简洁。在关于动画兼容方面,github上的大牛Jake Wharton又做了一套动画开源库NineOldAndroids,效果很好而且支持3.0级以前的版本,确实很值得称赞。而在此基础上,有很多高手又做了二次封装,实现了复杂动画,同时保证方便简洁,而且通用性和扩展性更高。我们这里的动画使用的就是这样一个简单的封装。
比如,要在XXView上时用XXAnimator这样的动画,持续Duration秒。就这么一行代码:
AnimHelper.with(new SlideOutUpAnimator()).duration(1000).playOn(textView);
来看一下基于NineOldAndroids的ViewAnimations具体实现。
这个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方法供其子类实现具体的动画效果。
当我们要实现具体的动画效果时,可以直接继承这个类并实现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。
首先定义了一个静态类,使用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); } } } }