Android動(dòng)畫工具類的封裝實(shí)戰(zhàn)記錄
起因
最近在做一個(gè)組件化框架的封裝,現(xiàn)在開發(fā)到一些常用工具類的封裝了,突然意識(shí)到好像還沒有做動(dòng)畫的工具類,于是開始著手開發(fā)之。
思路
既然要做動(dòng)畫,肯定是要做屬性動(dòng)畫的工具類的封裝了,由于補(bǔ)間動(dòng)畫和逐幀動(dòng)畫并不能改變目標(biāo)動(dòng)畫主題的實(shí)際屬性,在Android的開發(fā)中已經(jīng)越來越少人去用這兩個(gè)動(dòng)畫框架做開發(fā)了,而屬性動(dòng)畫則相對(duì)的越來越廣泛的使用在開發(fā)過程中了,于是這次的工具類的封裝,只針對(duì)屬性動(dòng)畫來封裝。
屬性動(dòng)畫對(duì)應(yīng)的類叫做ObjectAnimator,主要就是用這個(gè)類來實(shí)現(xiàn)動(dòng)畫的一些基礎(chǔ)設(shè)置,其具體的使用方式我就不寫了,有興趣的朋友可以自行學(xué)習(xí)屬性動(dòng)畫的相關(guān)知識(shí)。
封裝屬性動(dòng)畫工具類不可避免的還要考慮到屬性動(dòng)畫的組合播放動(dòng)畫的需求,而屬性動(dòng)畫的組合播放有大約三種方式:
1.使用AnimatorSet的Builder來組合播放
AnimatorSet.Builder是一個(gè)使用的動(dòng)畫工具類,用于方便向AnimatorSet添加動(dòng)畫以及設(shè)置各種動(dòng)畫之間的關(guān)系。在 AnimatorSet.Builder中,共聲明了after(long)、after(Animator)、before(Animator)、with(Animator)等四個(gè)方法。
- after(delay) 設(shè)置動(dòng)畫延遲delay時(shí)間后播放
- after(anim) 設(shè)置在anim動(dòng)畫結(jié)束后播放此動(dòng)畫
- before(anim) 設(shè)置此動(dòng)畫早于anim播放
- with(anim) 設(shè)置此動(dòng)畫與anim一起播放
然后再調(diào)用paly(anim)方法來鏈?zhǔn)秸{(diào)用動(dòng)畫
AnimatorSet set=new AnimatorSet(); set.play(anim1).before(anim2).with(anim3).after(anim4);
我們注意到他是先執(zhí)行的after,然后是play和with同時(shí)執(zhí)行,最后執(zhí)行的before。所以大家記住這個(gè)順序,無論怎么寫,都是這個(gè)執(zhí)行順序。
2.使用AnimatorSet的playSequentially
API
- playSequentially(List items):添加一組動(dòng)畫,播放順序?yàn)橹鹨徊シ?/li>
- playSequentially(Animator… items):添加一組動(dòng)畫,播放順序?yàn)橹鹨徊シ?/li>
AnimatorSet bouncer = new AnimatorSet(); ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_X, 0f, 300f); ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_Y, 0f, 300f); ObjectAnimator objectAnimatorC = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_ROTATION, 0f, 360f); bouncer.playSequentially(objectAnimatorA, objectAnimatorB, objectAnimatorC); bouncer.setDuration(6000); bouncer.start();
3.使用AnimatorSet的palyTogether
API
- playTogether(Collection items):添加一組動(dòng)畫,播放順序?yàn)橐黄鸩シ?/li>
- playTogether(Animator… items):添加一組動(dòng)畫,播放順序?yàn)橐黄鸩シ?/li>
AnimatorSet bouncer = new AnimatorSet(); ObjectAnimator objectAnimatorA = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_X, 0f, 300f); ObjectAnimator objectAnimatorB = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_TRANSLATION_Y, 0f, 300f); ObjectAnimator objectAnimatorC = ObjectAnimator.ofFloat(btnProperty, PropertyConstant.PROPERTY_ROTATION, 0f, 360f); bouncer.playSequentially(objectAnimatorA, objectAnimatorB, objectAnimatorC); bouncer.setDuration(6000); bouncer.start();
掌握以上的知識(shí)點(diǎn)后,我的思路是,其實(shí)最后就是對(duì)執(zhí)行方式的封裝,所謂的執(zhí)行方式就是如何正常的調(diào)用play,playSequentially和playTogether三個(gè)方法,這里需要合理的封裝。
還有就是對(duì)于監(jiān)聽接口的封裝,每個(gè)ObjectAnimator都有三個(gè)接口:
Animator.AnimatorListener 對(duì)整個(gè)動(dòng)畫生命周期的監(jiān)聽
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
Toast.makeText(MainActivity.this, "start", Toast.LENGTH_LONG).show();
}
@Override
public void onAnimationEnd(Animator animator) {
Toast.makeText(MainActivity.this, "End", Toast.LENGTH_LONG).show();
}
@Override
public void onAnimationCancel(Animator animator) {
Toast.makeText(MainActivity.this, "Cancel", Toast.LENGTH_LONG).show();
}
@Override
public void onAnimationRepeat(Animator animator) {
Toast.makeText(MainActivity.this, "rapeat", Toast.LENGTH_LONG).show();
}
});
anim.start();
ValueAnimator.AnimatorUpdateListener 對(duì)于該動(dòng)畫逐幀的監(jiān)聽
ValueAnimator vanim = ValueAnimator.ofInt(0,10,20);
vanim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//如果之前的ValueAnimtor指定的是Int的i話,那么返回的Value就是int類型,
也就是返回值類型與你創(chuàng)建的類型一致
int value = (int) valueAnimator.getAnimatedValue();
}
});
Animator.AnimatorPauseListener 對(duì)于該動(dòng)畫的暫停和播放的監(jiān)聽
new Animator.AnimatorPauseListener() {
@Override
public void onAnimationPause(Animator animator) {
}
@Override
public void onAnimationResume(Animator animator) {
}
}
由于我的初步構(gòu)想是使用建造者模式的鏈?zhǔn)秸{(diào)用模式來設(shè)計(jì)我的工具類,如果按照普通的寫法,那么整個(gè)監(jiān)聽接口的設(shè)置將會(huì)是災(zāi)難性的,因?yàn)樗械谋O(jiān)聽接口的設(shè)置都是混亂的,所以這里必須處理,我的思路是,學(xué)習(xí)SpringSecurity的鏈?zhǔn)秸{(diào)用設(shè)計(jì),為每個(gè)類型的監(jiān)聽設(shè)置自己的類,然后再讓工具主類調(diào)用該類型的監(jiān)聽接口,然后設(shè)置完畢后,在通過該監(jiān)聽接口類的and()方法回到工具類的主類型來,這樣在鏈?zhǔn)秸{(diào)用的時(shí)候就有一個(gè)起止順序,不會(huì)混亂執(zhí)行了,而且如果不用設(shè)置監(jiān)聽,不調(diào)用監(jiān)聽類設(shè)置也不會(huì)影響主類的執(zhí)行。
截取關(guān)鍵代碼,以Play方法的監(jiān)聽接口設(shè)置為例:
/**
*工具類的主類
**/
public static class AnimatorSetWrap{
PlayAnimationListener playListener;
public PlayAnimationListener toAddPlayListener(){
playListener=new PlayAnimationListener(this);
return playListener;
}
}
/**
* Play方法對(duì)應(yīng)的ObjectAnimator的監(jiān)聽實(shí)例
*/
public static class PlayAnimationListener implements IAnimatorListener<PlayAnimationListener>{
private Animator.AnimatorListener animatorListener;
private ValueAnimator.AnimatorUpdateListener updateListener;
private Animator.AnimatorPauseListener pauseListener;
public AnimatorSetWrap animatorSetWrap;
public PlayAnimationListener(AnimatorSetWrap animatorSetWrap){
this.animatorSetWrap=animatorSetWrap;
}
@Override
public PlayAnimationListener setAnimatorListener(Animator.AnimatorListener animatorListener) {
this.animatorListener=animatorListener;
return this;
}
@Override
public PlayAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener animatorListener) {
this.updateListener=animatorListener;
return this;
}
@Override
public PlayAnimationListener setPauseListener(Animator.AnimatorPauseListener animatorListener) {
this.pauseListener=animatorListener;
return this;
}
@Override
public AnimatorSetWrap and(){
return animatorSetWrap;
}
}
/**
* 動(dòng)畫監(jiān)聽的公用模板接口
* @param <T>
*/
interface IAnimatorListener<T>{
/**
* 設(shè)置AnimatorListener的方法
* @param listener
* @return
*/
T setAnimatorListener(Animator.AnimatorListener listener);
/**
* 設(shè)置AnimatorUpdateListener的方法
* @param listener
* @return
*/
T setUpdateListener(ValueAnimator.AnimatorUpdateListener listener);
/**
* 設(shè)置AnimatorPauseListener的方法
* @param listener
* @return
*/
T setPauseListener(Animator.AnimatorPauseListener listener);
/**
* 橋接動(dòng)畫監(jiān)聽與動(dòng)畫工具類的方法
* @return
*/
AnimatorSetWrap and();
}
具體的使用方法:
AnimatorUtil.AnimatorSetWrap animatorSetWrapDemo=new AnimatorSetWrap().toAddPlayListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
LogUtils.e("數(shù)值:"+valueAnimator.getAnimatedValue());
}
}).and();
通過這種鏈?zhǔn)秸{(diào)用,只要調(diào)用到and()方法就又回到了AnimatorSetWrap工具類的實(shí)例,剩下就可以繼續(xù)調(diào)用其他動(dòng)畫的方法并播放動(dòng)畫了。
代碼
說了這么多,就把我的工具類代碼分享給大家吧,可能還不完善,有什么問題大家一起探討:
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
import android.view.View;
import android.view.animation.LinearInterpolator;
import java.util.ArrayList;
import java.util.List;
/**
* 動(dòng)畫工具類
*@package com.dhcc.commonutils
*@author jasoncool
*@createDate 2018/11/20 16:16
*@description
**/
public class AnimatorUtils {
public static final String ALPHA="Alpha";
public static final String TRANSX="TranslationX";
public static final String TRANSY="TranslationY";
public static final String SCALEX="ScaleX";
public static final String SCALEY="ScaleY";
public static final String ROTATION="Rotation";
public static final String ROTATIONX="RotationX";
public static final String ROTATIONY="RotationY";
/**
* 默認(rèn)的TimeInterpolator,前后減速,中間加速
*/
private static final TimeInterpolator sDefaultInterpolator =
new LinearInterpolator();
public static AnimatorSetWrap createAnimator() {
return new AnimatorSetWrap();
}
/**
* @param interpolator 默認(rèn)的TimeInterpolator
* @return
*/
public static AnimatorSetWrap createAnimator(TimeInterpolator interpolator) {
return new AnimatorSetWrap(interpolator);
}
/**
* 屬性動(dòng)畫組合
* 屬性動(dòng)畫組合對(duì)應(yīng)的是AnimatorSet類,我們只需要new他就好。
*
* 它對(duì)應(yīng)的主要有這四個(gè)方法,play,before,with,after。
* 這四個(gè)方法里面全都是填入往后兒們的animator類,
* 但是先后執(zhí)行順序不一樣,分別對(duì)應(yīng)著開啟,最后,同步,最開始執(zhí)行。
* 我們注意到他是先執(zhí)行的after,然后是play和with同時(shí)執(zhí)行,最后執(zhí)行的before。
* 所以大家記住這個(gè)順序,無論怎么寫,都是這個(gè)執(zhí)行順序。
*
*/
public static class AnimatorSetWrap{
private View mView;
/**
* 不設(shè)置默認(rèn)插值器時(shí),工具類自帶的默認(rèn)插值器
*/
private TimeInterpolator mTimeInterpolator;
/**
* 判斷play方法只允許執(zhí)行一次的布爾值
*/
boolean mIsPlaying=false;
/**
* 聯(lián)合動(dòng)畫的動(dòng)畫容器
*/
private AnimatorSet mAnimatorSet;
/**
* 聯(lián)合動(dòng)畫的動(dòng)畫構(gòu)造器
*/
private AnimatorSet.Builder mAnimatorBuilder;
/**
* 默認(rèn)執(zhí)行時(shí)間
*/
private int mDuration=1000;
/**
* play的監(jiān)聽器類
*/
PlayAnimationListener playListener;
/**
* before的監(jiān)聽器類
*/
BeforeAnimationListener beforeListener;
/**
* with的監(jiān)聽器類
*/
WithAnimationListener withListener;
/**
* after的監(jiān)聽器類
*/
AfterAnimationListener afterListener;
/**
* then的監(jiān)聽器類
*/
ThenAnimationListener thenListener;
/**
* 順序播放或者同時(shí)播放時(shí)存儲(chǔ)動(dòng)畫的列表容器
*/
List<Animator> mAnimatorList;
/**
* 是否已經(jīng)初始化then動(dòng)畫
*/
boolean mHasInitThenAnim=false;
private AnimatorSetWrap(){
this(sDefaultInterpolator);
}
/**
* 構(gòu)造方法
* 主要是負(fù)責(zé)
* 1.初始化默認(rèn)的插值器 mTimeInterpolator
* 2.初始化聯(lián)合動(dòng)畫Set mAnimatorSet
* 3.初始化順序或同時(shí)播放動(dòng)畫容器 mAnimatorList
* @param interpolator
*/
private AnimatorSetWrap(TimeInterpolator interpolator) {
mTimeInterpolator = interpolator;
mAnimatorSet = new AnimatorSet();
mAnimatorList=new ArrayList<>(16);
}
/**
* Play動(dòng)畫的監(jiān)聽啟動(dòng)方法
* 如果要監(jiān)聽play動(dòng)畫先調(diào)用這個(gè)方法
* @return
*/
public PlayAnimationListener toAddPlayListener(){
playListener=new PlayAnimationListener(this);
return playListener;
}
/**
* Before動(dòng)畫的監(jiān)聽啟動(dòng)方法
* 如果要監(jiān)聽Before動(dòng)畫先調(diào)用這個(gè)方法
* @return
*/
public BeforeAnimationListener toAddBeforeListener(){
beforeListener=new BeforeAnimationListener(this);
return beforeListener;
}
/**
* With動(dòng)畫的監(jiān)聽啟動(dòng)方法
* 如果要監(jiān)聽With動(dòng)畫先調(diào)用這個(gè)方法
* @return
*/
public WithAnimationListener toAddWithListener(){
withListener=new WithAnimationListener(this);
return withListener;
}
/**
* After動(dòng)畫的監(jiān)聽啟動(dòng)方法
* 如果要監(jiān)聽After動(dòng)畫先調(diào)用這個(gè)方法
* @return
*/
public AfterAnimationListener toAddAfterListener(){
afterListener=new AfterAnimationListener(this);
return afterListener;
}
/**
* 順序或同時(shí)播放動(dòng)畫執(zhí)行時(shí)的監(jiān)聽方法
* 要先于Then方法進(jìn)行調(diào)用
* @return
*/
public ThenAnimationListener toAddThenListener(){
thenListener=new ThenAnimationListener(this);
return thenListener;
}
/**
* 順序或者同時(shí)播放動(dòng)畫時(shí)的調(diào)用方法
* 在其內(nèi)部生成一個(gè)Animator并將該Animator加入到mAnimatorList中備用
* @param view 動(dòng)畫執(zhí)行的主體View
* @param animName 動(dòng)畫類型
* @param interpolator 動(dòng)畫插值器 如果不設(shè)置就用默認(rèn)的
* @param repeatCount 重復(fù)次數(shù)
* @param duration 執(zhí)行時(shí)間
* @param values 動(dòng)畫執(zhí)行的值
* @return
*/
public AnimatorSetWrap then(View view, String animName, @Nullable TimeInterpolator interpolator, @Size(min = 0,max=Integer.MAX_VALUE) int repeatCount, @Size(min = 0,max=Integer.MAX_VALUE) int duration, float... values){
LogUtils.e("addThen");
if(view==null){
throw new RuntimeException("view 不能為空");
}
mIsPlaying = true;
mView = view;
ObjectAnimator thenAnimator = ObjectAnimator.ofFloat(view,animName,values);
thenAnimator.setInterpolator(interpolator==null?mTimeInterpolator:interpolator);
thenAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
thenAnimator.setDuration(duration<0?mDuration:duration);
if (thenListener!=null&&thenListener.animatorListener != null) {
thenAnimator.addListener(thenListener.animatorListener);
}
if(thenListener!=null&&thenListener.updateListener!=null){
thenAnimator.addUpdateListener(thenListener.updateListener);
}
if(thenListener!=null&&thenListener.pauseListener!=null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
thenAnimator.addPauseListener(thenListener.pauseListener);
}else{
throw new RuntimeException("SDK最小要求19");
}
}
mAnimatorList.add(thenAnimator);
return this;
}
public AnimatorSetWrap then(Animator animator) {
mAnimatorList.add(animator);
return this;
}
public AnimatorSetWrap then(AnimatorSetWrap animator) {
mAnimatorList.add(animator.getAnimatorSet());
return this;
}
/**
* AnimatorSet的Play方法,整個(gè)動(dòng)畫過程只能調(diào)用一次
* 并且一旦執(zhí)行play方法將會(huì)清除掉mAnimatorList中存儲(chǔ)的順序或同時(shí)執(zhí)行的方法實(shí)例
* @param view 方法主體
* @param animName 動(dòng)畫類型
* @param interpolator 插值器
* @param repeatCount 重復(fù)次數(shù)
* @param duration 動(dòng)畫時(shí)長
* @param values 動(dòng)畫執(zhí)行值
* @return
*/
public AnimatorSetWrap play(View view, String animName, @Nullable TimeInterpolator interpolator, @Size(min = 0,max=Integer.MAX_VALUE) int repeatCount, @Size(min = 0,max=Integer.MAX_VALUE) int duration, float... values){
LogUtils.e("play");
if(mIsPlaying){
throw new RuntimeException("AnimatorSetWrap.play()方法只能調(diào)用一次");
}
if(view==null){
throw new RuntimeException("view 不能為空");
}
mIsPlaying = true;
mView = view;
ObjectAnimator playAnimator = ObjectAnimator.ofFloat(view,animName,values);
playAnimator.setInterpolator(interpolator==null?mTimeInterpolator:interpolator);
playAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
playAnimator.setDuration(duration<0?mDuration:duration);
if (playListener!=null&&playListener.animatorListener != null) {
playAnimator.addListener(playListener.animatorListener);
}
if(playListener!=null&&playListener.updateListener!=null){
playAnimator.addUpdateListener(playListener.updateListener);
}
if(playListener!=null&&playListener.pauseListener!=null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
playAnimator.addPauseListener(playListener.pauseListener);
}else{
throw new RuntimeException("SDK最小要求19");
}
}
mAnimatorList.clear();
mAnimatorBuilder=mAnimatorSet.play(playAnimator);
return this;
}
public AnimatorSetWrap play(Animator animator) {
mAnimatorList.clear();
mAnimatorBuilder = mAnimatorSet.play(animator);
return this;
}
public AnimatorSetWrap play(AnimatorSetWrap animator) {
mAnimatorList.clear();
mAnimatorBuilder = mAnimatorSet.play(animator.getAnimatorSet());
return this;
}
/**
* AnimatorSet的Before方法
* @param view 動(dòng)畫執(zhí)行的主體View
* @param animName 動(dòng)畫類型
* @param interpolator 插值器
* @param repeatCount 重復(fù)次數(shù)
* @param duration 動(dòng)畫執(zhí)行時(shí)長
* @param values 動(dòng)畫執(zhí)行數(shù)值
* @return
*/
public AnimatorSetWrap before(View view, String animName,@Nullable TimeInterpolator interpolator, @Size(min = 0,max=Integer.MAX_VALUE) int repeatCount,@Size(min = 0,max=Integer.MAX_VALUE)int duration, float... values){
LogUtils.e("before");
if(view==null){
throw new RuntimeException("view 不能為空");
}
ObjectAnimator beforeAnimator = ObjectAnimator.ofFloat(view,
animName, values).setDuration(duration);
beforeAnimator.setInterpolator(interpolator==null?mTimeInterpolator:interpolator);
beforeAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
beforeAnimator.setDuration(duration<0?mDuration:duration);
if (beforeListener!=null&&beforeListener.animatorListener != null) {
beforeAnimator.addListener(beforeListener.animatorListener);
}
if(beforeListener!=null&&beforeListener.updateListener!=null){
beforeAnimator.addUpdateListener(beforeListener.updateListener);
}
if(beforeListener!=null&&beforeListener.pauseListener!=null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
beforeAnimator.addPauseListener(beforeListener.pauseListener);
}else{
throw new RuntimeException("SDK最小要求19");
}
}
mAnimatorBuilder = mAnimatorBuilder.before(beforeAnimator);
return this;
}
public AnimatorSetWrap before(Animator animator) {
mAnimatorBuilder = mAnimatorBuilder.before(animator);
return this;
}
public AnimatorSetWrap before(AnimatorSetWrap animator) {
mAnimatorBuilder = mAnimatorBuilder.before(animator.getAnimatorSet());
return this;
}
public AnimatorSetWrap with(View view, String animName,@Nullable TimeInterpolator interpolator,@Size(min = 0,max=Integer.MAX_VALUE) int repeatCount,@Size(min = 0,max=Integer.MAX_VALUE)int duration, float... values){
LogUtils.e("with");
if(view==null){
throw new RuntimeException("view 不能為空");
}
ObjectAnimator withAnimator = ObjectAnimator.ofFloat(view,
animName, values).setDuration(duration);
withAnimator.setInterpolator(interpolator==null?mTimeInterpolator:interpolator);
withAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
withAnimator.setDuration(duration<0?mDuration:duration);
if (withListener!=null&&withListener.animatorListener != null) {
withAnimator.addListener(withListener.animatorListener);
}
if(withListener!=null&&withListener.updateListener!=null){
withAnimator.addUpdateListener(withListener.updateListener);
}
if(withListener!=null&&withListener.pauseListener!=null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
withAnimator.addPauseListener(withListener.pauseListener);
}else{
throw new RuntimeException("SDK最小要求19");
}
}
mAnimatorBuilder = mAnimatorBuilder.with(withAnimator);
return this;
}
public AnimatorSetWrap with(Animator animator) {
mAnimatorBuilder = mAnimatorBuilder.with(animator);
return this;
}
public AnimatorSetWrap with(AnimatorSetWrap animator) {
mAnimatorBuilder = mAnimatorBuilder.with(animator.getAnimatorSet());
return this;
}
public AnimatorSetWrap after(View view, String animName,@Nullable TimeInterpolator interpolator,@Size(min = 0,max=Integer.MAX_VALUE) int repeatCount,@Size(min = 0,max=Integer.MAX_VALUE) int duration, float... values){
LogUtils.e("after");
if(view==null){
throw new RuntimeException("view 不能為空");
}
ObjectAnimator afterAnimator = ObjectAnimator.ofFloat(view,
animName, values).setDuration(duration);
afterAnimator.setInterpolator(interpolator==null?mTimeInterpolator:interpolator);
afterAnimator.setRepeatCount(repeatCount<0?0:repeatCount);
afterAnimator.setDuration(duration<0?mDuration:duration);
if (afterListener!=null&&afterListener.animatorListener != null) {
afterAnimator.addListener(afterListener.animatorListener);
}
if(afterListener!=null&&afterListener.updateListener!=null){
afterAnimator.addUpdateListener(afterListener.updateListener);
}
if(afterListener!=null&&afterListener.pauseListener!=null){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
afterAnimator.addPauseListener(afterListener.pauseListener);
}else{
throw new RuntimeException("SDK最小要求19");
}
}
mAnimatorBuilder = mAnimatorBuilder.after(afterAnimator);
return this;
}
public AnimatorSetWrap after(Animator animator) {
mAnimatorBuilder = mAnimatorBuilder.after(animator);
return this;
}
public AnimatorSetWrap after(AnimatorSetWrap animator) {
mAnimatorBuilder = mAnimatorBuilder.after(animator.getAnimatorSet());
return this;
}
public AnimatorSetWrap after(long delay) {
mAnimatorBuilder.after(delay);
return this;
}
/**
* 直接執(zhí)行動(dòng)畫,該動(dòng)畫操作主要用作執(zhí)行AnimatorSet的組合動(dòng)畫
* 如果mAnimatorList不為0 則執(zhí)行逐一播放動(dòng)畫
*/
public void playAnim() {
if(mAnimatorList.size()>0){
readyThen(true);
}
mAnimatorSet.start();
}
/**
* 在一定時(shí)長內(nèi)運(yùn)行完該組合動(dòng)畫
* 如果mAnimatorList不為0 則執(zhí)行逐一播放動(dòng)畫
* @param duration 動(dòng)畫時(shí)長
*/
public void playAnim(long duration) {
if(mAnimatorList.size()>0){
readyThen(true);
}
mAnimatorSet.setDuration(duration);
mAnimatorSet.start();
}
/**
* 延遲一定時(shí)長播放動(dòng)畫
* 如果mAnimatorList不為0 則執(zhí)行逐一播放動(dòng)畫
* @param delay 延遲時(shí)長
*/
public void playAnimDelay(long delay) {
if(mAnimatorList.size()>0){
readyThen(true);
}
mAnimatorSet.setStartDelay(delay);
mAnimatorSet.start();
}
/**
* 直接執(zhí)行動(dòng)畫,該動(dòng)畫操作主要用作執(zhí)行AnimatorSet的組合動(dòng)畫
*/
public void playAnim(boolean isSequentially) {
readyThen(isSequentially);
mAnimatorSet.start();
}
/**
* 在一定時(shí)長內(nèi)運(yùn)行完該組合動(dòng)畫
* @param duration 動(dòng)畫時(shí)長
*/
public void playAnim(boolean isSequentially,long duration) {
readyThen(isSequentially);
mAnimatorSet.setDuration(duration);
mAnimatorSet.start();
}
/**
* 延遲一定時(shí)長播放動(dòng)畫
* @param delay 延遲時(shí)長
*/
public void playAnimDelay(boolean isSequentially,long delay) {
readyThen(isSequentially);
mAnimatorSet.setStartDelay(delay);
mAnimatorSet.start();
}
/**
* 順序播放動(dòng)畫
* @param isSequentially 是逐一播放還是同時(shí)播放
*/
private void readyThen(boolean isSequentially){
// 只在第一次啟動(dòng)時(shí)初始化
if (mHasInitThenAnim) {
return;
}
mHasInitThenAnim = true;
if (mAnimatorList.size() > 0) {
AnimatorSet set = new AnimatorSet();
if(isSequentially){
set.playSequentially(mAnimatorList);
}else{
set.playTogether(mAnimatorList);
}
mAnimatorBuilder.before(set);
}
}
/**
* 取消動(dòng)畫
*/
public void cancel() {
mAnimatorSet.cancel();
mAnimatorList.clear();
}
/**
* 獲取AnimatorSet的實(shí)例
* @return
*/
private AnimatorSet getAnimatorSet() {
return mAnimatorSet;
}
/**
* 為AnimatorSet設(shè)置監(jiān)聽
* @param listener
* @return
*/
public AnimatorSetWrap setAnimatorSetListener(Animator.AnimatorListener listener) {
mAnimatorSet.addListener(listener);
return this;
}
/**
* 取消AnimatorSet的監(jiān)聽
* @param listener
*/
public void removeSetListner(Animator.AnimatorListener listener) {
mAnimatorSet.removeListener(listener);
}
/**
* 取消全部AnimatorSet的監(jiān)聽
*/
public void removeAllLSetisteners() {
mAnimatorSet.removeAllListeners();
}
/**
* 判斷一個(gè)View是否在當(dāng)前的屏幕中可見(肉眼真實(shí)可見)
* @param mView
* @return 返回true則可見
*/
public static boolean isVisibleOnScreen(View mView) {
if (mView == null) {
return false;
}
return mView.getWindowVisibility() == View.VISIBLE
&& mView.getVisibility() == View.VISIBLE && mView.isShown();
}
}
/**
* Play方法對(duì)應(yīng)的ObjectAnimator的監(jiān)聽實(shí)例
*/
public static class PlayAnimationListener implements IAnimatorListener<PlayAnimationListener>{
private Animator.AnimatorListener animatorListener;
private ValueAnimator.AnimatorUpdateListener updateListener;
private Animator.AnimatorPauseListener pauseListener;
public AnimatorSetWrap animatorSetWrap;
public PlayAnimationListener(AnimatorSetWrap animatorSetWrap){
this.animatorSetWrap=animatorSetWrap;
}
@Override
public PlayAnimationListener setAnimatorListener(Animator.AnimatorListener animatorListener) {
this.animatorListener=animatorListener;
return this;
}
@Override
public PlayAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener animatorListener) {
this.updateListener=animatorListener;
return this;
}
@Override
public PlayAnimationListener setPauseListener(Animator.AnimatorPauseListener animatorListener) {
this.pauseListener=animatorListener;
return this;
}
@Override
public AnimatorSetWrap and(){
return animatorSetWrap;
}
}
public static class BeforeAnimationListener implements IAnimatorListener<BeforeAnimationListener>{
private Animator.AnimatorListener animatorListener;
private ValueAnimator.AnimatorUpdateListener updateListener;
private Animator.AnimatorPauseListener pauseListener;
public AnimatorSetWrap animatorSetWrap;
public BeforeAnimationListener(AnimatorSetWrap animatorSetWrap){
this.animatorSetWrap=animatorSetWrap;
}
@Override
public AnimatorSetWrap and() {
return animatorSetWrap;
}
@Override
public BeforeAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
this.animatorListener=listener;
return this;
}
@Override
public BeforeAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
this.updateListener=listener;
return this;
}
@Override
public BeforeAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
this.pauseListener=listener;
return this;
}
}
public static class WithAnimationListener implements IAnimatorListener<WithAnimationListener>{
private Animator.AnimatorListener animatorListener;
private ValueAnimator.AnimatorUpdateListener updateListener;
private Animator.AnimatorPauseListener pauseListener;
public AnimatorSetWrap animatorSetWrap;
public WithAnimationListener(AnimatorSetWrap animatorSetWrap){
this.animatorSetWrap=animatorSetWrap;
}
@Override
public AnimatorSetWrap and() {
return animatorSetWrap;
}
@Override
public WithAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
this.animatorListener=listener;
return this;
}
@Override
public WithAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
this.updateListener=listener;
return this;
}
@Override
public WithAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
this.pauseListener=listener;
return this;
}
}
public static class AfterAnimationListener implements IAnimatorListener<AfterAnimationListener>{
private Animator.AnimatorListener animatorListener;
private ValueAnimator.AnimatorUpdateListener updateListener;
private Animator.AnimatorPauseListener pauseListener;
public AnimatorSetWrap animatorSetWrap;
public AfterAnimationListener(AnimatorSetWrap animatorSetWrap){
this.animatorSetWrap=animatorSetWrap;
}
@Override
public AnimatorSetWrap and() {
return animatorSetWrap;
}
@Override
public AfterAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
this.animatorListener=listener;
return this;
}
@Override
public AfterAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
this.updateListener=listener;
return this;
}
@Override
public AfterAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
this.pauseListener=listener;
return this;
}
}
public static class ThenAnimationListener implements IAnimatorListener<ThenAnimationListener>{
private Animator.AnimatorListener animatorListener;
private ValueAnimator.AnimatorUpdateListener updateListener;
private Animator.AnimatorPauseListener pauseListener;
public AnimatorSetWrap animatorSetWrap;
public ThenAnimationListener(AnimatorSetWrap animatorSetWrap){
this.animatorSetWrap=animatorSetWrap;
}
@Override
public AnimatorSetWrap and() {
return animatorSetWrap;
}
@Override
public ThenAnimationListener setAnimatorListener(Animator.AnimatorListener listener) {
this.animatorListener=listener;
return this;
}
@Override
public ThenAnimationListener setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
this.updateListener=listener;
return this;
}
@Override
public ThenAnimationListener setPauseListener(Animator.AnimatorPauseListener listener) {
this.pauseListener=listener;
return this;
}
}
/**
* 動(dòng)畫監(jiān)聽的公用模板接口
* @param <T>
*/
interface IAnimatorListener<T>{
/**
* 設(shè)置AnimatorListener的方法
* @param listener
* @return
*/
T setAnimatorListener(Animator.AnimatorListener listener);
/**
* 設(shè)置AnimatorUpdateListener的方法
* @param listener
* @return
*/
T setUpdateListener(ValueAnimator.AnimatorUpdateListener listener);
/**
* 設(shè)置AnimatorPauseListener的方法
* @param listener
* @return
*/
T setPauseListener(Animator.AnimatorPauseListener listener);
/**
* 橋接動(dòng)畫監(jiān)聽與動(dòng)畫工具類的方法
* @return
*/
AnimatorSetWrap and();
}
}
使用方法:
AnimatorUtils.createAnimator().play(viewAnimator,AnimatorUtils.ROTATIONY,null,0,1000,0,360).toAddThenListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
LogUtils.e("then1:"+valueAnimator.getAnimatedValue());
}
}).and().then(viewAnimator, AnimatorUtils.TRANSY, null, -1, -2, 0, 100, 200, 300, 200, 100, 0).toAddThenListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
LogUtils.e("then2:"+valueAnimator.getAnimatedValue());
}
}).and().then(viewAnimator, AnimatorUtils.SCALEX, new LinearInterpolator(), 0, 1000, 0, 10).toAddWithListener().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
LogUtils.e("with1:"+valueAnimator.getAnimatedValue());
}
}).and().with(viewAnimator, AnimatorUtils.SCALEY, new LinearInterpolator(), 0, 1000, 0, 10).toAddWithListener().setAnimatorListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
LogUtils.e("with2:onAnimationStart");
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
}).and().with(viewAnimator, AnimatorUtils.ALPHA, new LinearInterpolator(), 0, 1000, 1, 0,1)
//.playSequentially(2000);
.playAnim();
上面的動(dòng)畫調(diào)用方法是我亂寫的,具體就是為了演示工具類的使用方法,你可以改成自己的調(diào)用方法。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Android自定義控件實(shí)現(xiàn)圓形進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)圓形進(jìn)度條的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
Android ListView分頁簡單實(shí)現(xiàn)
這篇文章主要介紹了Android ListView分頁簡單實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android實(shí)現(xiàn)多級(jí)列表中的新建功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)多級(jí)列表中的新建功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
Android實(shí)現(xiàn)帶有進(jìn)度條的按鈕效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)帶有進(jìn)度條的按鈕效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
Android 中自定義Dialog樣式的Activity點(diǎn)擊空白處隱藏軟鍵盤功能(dialog不消失)
項(xiàng)目中需要開發(fā)帶有EditText的Dialog顯示,要求在編輯完EditText時(shí),點(diǎn)擊Dilog的空白處隱藏軟鍵盤。但是Dialog不會(huì)消失。下面通過實(shí)例代碼給大家分享實(shí)現(xiàn)方法,需要的的朋友參考下吧2017-04-04
Android實(shí)現(xiàn)通話自動(dòng)錄音
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)通話自動(dòng)錄音,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
Android控件Chronometer定時(shí)器的實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了Android控件Chronometer定時(shí)器的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11

