您的位置:首页 > 移动开发 > Android开发

android 属性动画入门

2016-07-10 00:28 423 查看
前面关于tween动画写了2篇博客,如果那2篇博客都看懂了,估计Tween动画理解使用起来问题就不大,之前也说了Tween动画的缺点就是在交互上有bug,今天就讲下属性动画,属性动画就能解决Tween动画交互上的问题,由于下周工作上很忙,估计要花一周时间把这篇博客写完,一些常见的动画demo,都在写出来,希望每个人都能看的懂,切入正题,

属性动画英文叫Property Animator,它包括ValueAnimator和ObjectAnimator,我们先看ValueAnimator这个类,从类名字直观的就是叫值动画,对吧,那么这和Tween动画不同的是Tween动画是叫view
animation,作用于控件上的,如果看过ValueAnimator类的源码就知道它是继承了Animator这个类,现在看下Animator类的源码,看看它给我们提供了什么方法让我们去调用,这个类的源码是我把注释删除了,代码量很少,才200多行

package android.animation;

import android.content.res.ConstantState;

import java.util.ArrayList;

public abstract class Animator implements Cloneable {

    /**

     * The set of listeners to be sent events through the life of an animation.

     */

    ArrayList<AnimatorListener> mListeners = null;

    /**

     * The set of listeners to be sent pause/resume events through the life

     * of an animation.

     */

    ArrayList<AnimatorPauseListener> mPauseListeners = null;

    /**

     * Whether this animator is currently in a paused state.

     */

    boolean mPaused = false;

  

    int mChangingConfigurations = 0;

    private AnimatorConstantState mConstantState;

    public void start() {

    }

    public void cancel() {

    }

    public void end() {

    }

    public void pause() {

        if (isStarted() && !mPaused) {

            mPaused = true;

            if (mPauseListeners != null) {

                ArrayList<AnimatorPauseListener> tmpListeners =

                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();

                int numListeners = tmpListeners.size();

                for (int i = 0; i < numListeners; ++i) {

                    tmpListeners.get(i).onAnimationPause(this);

                }

            }

        }

    }

    public void resume() {

        if (mPaused) {

            mPaused = false;

            if (mPauseListeners != null) {

                ArrayList<AnimatorPauseListener> tmpListeners =

                        (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();

                int numListeners = tmpListeners.size();

                for (int i = 0; i < numListeners; ++i) {

                    tmpListeners.get(i).onAnimationResume(this);

                }

            }

        }

    }

    public boolean isPaused() {

        return mPaused;

    }

    public abstract long getStartDelay();

    public abstract void setStartDelay(long startDelay);

    public abstract Animator setDuration(long duration);

    public abstract long getDuration();

    public abstract void setInterpolator(TimeInterpolator value);

    public TimeInterpolator getInterpolator() {

        return null;

    }

    public abstract boolean isRunning();

    public boolean isStarted() {

        // Default method returns value for isRunning(). Subclasses should override to return a

        // real value.

        return isRunning();

    }

    public void addListener(AnimatorListener listener) {

        if (mListeners == null) {

            mListeners = new ArrayList<AnimatorListener>();

        }

        mListeners.add(listener);

    }

    public void removeListener(AnimatorListener listener) {

        if (mListeners == null) {

            return;

        }

        mListeners.remove(listener);

        if (mListeners.size() == 0) {

            mListeners = null;

        }

    } 

    public ArrayList<AnimatorListener> getListeners() {

        return mListeners;

    }

    public void addPauseListener(AnimatorPauseListener listener) {

        if (mPauseListeners == null) {

            mPauseListeners = new ArrayList<AnimatorPauseListener>();

        }

        mPauseListeners.add(listener);

    } 

    public void removePauseListener(AnimatorPauseListener listener) {

        if (mPauseListeners == null) {

            return;

        }

        mPauseListeners.remove(listener);

        if (mPauseListeners.size() == 0) {

            mPauseListeners = null;

        }

    }

    public void removeAllListeners() {

        if (mListeners != null) {

            mListeners.clear();

            mListeners = null;

        }

        if (mPauseListeners != null) {

            mPauseListeners.clear();

            mPauseListeners = null;

        }

    }

    public int getChangingConfigurations() {

        return mChangingConfigurations;

    }

    public void setChangingConfigurations(int configs) {

        mChangingConfigurations = configs;

    } 

    public void appendChangingConfigurations(int configs) {

        mChangingConfigurations |= configs;

    }

    public ConstantState<Animator> createConstantState() {

        return new AnimatorConstantState(this);

    }

    @Override

    public Animator clone() {

        try {

            final Animator anim = (Animator) super.clone();

            if (mListeners != null) {

                anim.mListeners = new ArrayList<AnimatorListener>(mListeners);

            }

            if (mPauseListeners != null) {

                anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners);

            }

            return anim;

        } catch (CloneNotSupportedException e) {

           throw new AssertionError();

        }

    }

    public void setupStartValues() {

    }

    public void setupEndValues() {

    }

    public void setTarget(Object target) {

    }

  

    public boolean canReverse() {

        return false;

    }

    /**

     * @hide

     */

    public void reverse() {

        throw new IllegalStateException("Reverse is not supported");

    }

    public static interface AnimatorListener { 

        void onAnimationStart(Animator animation);

        void onAnimationEnd(Animator animation);

        void onAnimationCancel(Animator animation);

        void onAnimationRepeat(Animator animation);

    }

    public static interface AnimatorPauseListener {

        void onAnimationPause(Animator animation);

        void onAnimationResume(Animator animation);

    }

    public void setAllowRunningAsynchronously(boolean mayRunAsync) {

        // It is up to subclasses to support this, if they can.

    }

    private static class AnimatorConstantState extends ConstantState<Animator> {

        final Animator mAnimator;

        int mChangingConf;

        public AnimatorConstantState(Animator animator) {

            mAnimator = animator;

            // ensure a reference back to here so that constante state is not gc'ed.

            mAnimator.mConstantState = this;

            mChangingConf = mAnimator.getChangingConfigurations();

        }

        @Override

        public int getChangingConfigurations() {

            return mChangingConf;

        }

        @Override

        public Animator newInstance() {

            final Animator clone = mAnimator.clone();

            clone.mConstantState = this;

            return clone;

        }

    }

}

通过看它的源码发现Animator是一个抽象类,既然它是抽象类,那么一定存在抽象的方法,现在就把几个抽象方法提出来

public abstract void setStartDelay(long startDelay); 这是延迟几秒开始执行动画

public abstract long getStartDelay();获取动画延迟执行的时间,单位为毫秒

 public abstract Animator setDuration(long duration); 设置动画执行的时间 单位为毫秒

 public abstract long getDuration();获取动画执行的时间

public abstract void setInterpolator(TimeInterpolator value);设置动画插值器

 public abstract boolean isRunning();动画是否在执行

下面是非抽象函数并且是空实现的

 public void start() {} 动画开始

  public void cancel() {}取消执行动画

public void end() {}结束动画执行

 public void setTarget(Object target) {}设置动画的标记

下面是非空实现方法:

public void pause() {}动画暂停的方法

public void resume() {}动画重新执行

public boolean isPaused() {}动画是否暂停了,默认返回值为false

public TimeInterpolator getInterpolator() {}  返回动画插值器对象,默认返回为null

public boolean isStarted() {} 动画是否执行了,默认返回值是调用了isRunning()方法,而这个方法又是抽象的,需要子类去实现,

public void addListener(AnimatorListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<AnimatorListener>();
}
mListeners.add(listener);
}

这是添加动画监听的方法,它是用一个List集合去维护了所添加的监听器,而AnimatorListener是一个接口,如下:

public static interface AnimatorListener {
/**
* <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);
}

这个接口分别定义了四个方法依次是动画开始,结束,取消,重复等回调接口,

public void removeListener(AnimatorListener listener) {
if (mListeners == null) {
return;
}
mListeners.remove(listener);
if (mListeners.size() == 0) {
mListeners = null;
}
}

这个是移除一个动画监听,

public ArrayList<AnimatorListener> getListeners() {
return mListeners;
}

这是获取所有监听动画

public void addPauseListener(AnimatorPauseListener listener) {
if (mPauseListeners == null) {
mPauseListeners = new ArrayList<AnimatorPauseListener>();
}
mPauseListeners.add(listener);
}

这是添加一个暂停动画监听的方法,而AnimatorPauseListener是一个接口

public static interface AnimatorPauseListener {
/**
* <p>Notifies that the animation was paused.</p>
*
* @param animation The animaton being paused.
* @see #pause()
*/
void onAnimationPause(Animator animation);

/**
* <p>Notifies that the animation was resumed, after being
* previously paused.</p>
*
* @param animation The animation being resumed.
* @see #resume()
*/
void onAnimationResume(Animator animation);
}

分别定义了动画暂停和重新执行的回调方法

public void removePauseListener(AnimatorPauseListener listener) {
if (mPauseListeners == null) {
return;
}
mPauseListeners.remove(listener);
if (mPauseListeners.size() == 0) {
mPauseListeners = null;
}
}

这是移除一个暂停动画的监听

public void removeAllListeners() {
if (mListeners != null) {
mListeners.clear();
mListeners = null;
}
if (mPauseListeners != null) {
mPauseListeners.clear();
mPauseListeners = null;
}
}

这是移除所有动画的监听,包括动画开始和结束的监听和暂停的监听

下面就开始讲ValueAnimator类的一些使用了,

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ValueAnimator animator = ValueAnimator.ofInt(0,100);
animator.setDuration(1000);
animator.start();
}
}

这是一个平移动画,但我并没有把这个动画作用于某一个控件上,那这个动画到底有没有执行呢?我们知道动画都有监听的方法,

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
Log.d(TAG,"curValue:"+curValue);
}
});

animation.getAnimatedValue()方法是返回动画的属性值,默认返回值是Object,但是我们传入的是int值,所以就可以强转成int值了,通过打印的log分析:

07-10 05:05:24.945 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:0

07-10 05:05:25.098 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:5

07-10 05:05:25.285 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:24

07-10 05:05:25.325 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:29

07-10 05:05:25.355 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:34

07-10 05:05:25.365 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:36

07-10 05:05:25.385 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:39

07-10 05:05:25.405 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:42

07-10 05:05:25.415 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:44

07-10 05:05:25.435 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:47

07-10 05:05:25.445 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:50

07-10 05:05:25.465 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:52

07-10 05:05:25.475 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:55

07-10 05:05:25.495 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:57

07-10 05:05:25.515 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:60

07-10 05:05:25.525 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:62

07-10 05:05:25.548 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:65

07-10 05:05:25.565 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:67

07-10 05:05:25.582 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:70

07-10 05:05:25.598 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:72

07-10 05:05:25.615 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:74

07-10 05:05:25.627 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:77

07-10 05:05:25.648 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:79

07-10 05:05:25.665 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:81

07-10 05:05:25.676 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:83

07-10 05:05:25.698 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:85

07-10 05:05:25.715 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:87

07-10 05:05:25.732 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:88

07-10 05:05:25.748 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:90

07-10 05:05:25.765 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:91

07-10 05:05:25.777 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:93

07-10 05:05:25.798 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:94

07-10 05:05:25.815 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:95

07-10 05:05:25.825 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:96

07-10 05:05:25.848 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:97

07-10 05:05:25.865 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:98

07-10 05:05:25.882 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:98

07-10 05:05:25.898 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:99

07-10 05:05:25.915 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:99

07-10 05:05:25.927 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:99

07-10 05:05:25.948 1178-1178/com.example.valueanimatordemo D/MainActivity: curValue:100

通过上面的log知道,上面是打印的在1秒时间内所改变的值,从这个log就证明动画是执行了的,但是并没有作用于某一个控件上,从这就明显看出来和Tween动画的区别,现在就根据这些值做一个平移的动画,你会发现view类并没有什么方法设置可以执行属性动画的方法,那我们只能根据view提供的并外一个方法layout动态改变他在父view上的位置了,这个方法大家很熟悉了,

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/btn_start_anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始动画"
android:layout_alignParentRight="true"
/>
<ImageView
android:id="@+id/iv_show_grid"
android:layout_width="100px"
android:layout_height="100px"
android:src="@mipmap/grid"
/>
</RelativeLayout>

这个imageview显示的图片是胡歌的前女友,只能说明星真会玩,玩了就不玩了,

public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Button btn_start_anim;
private ImageView iv_show_grid;
private int left,top;
private boolean isFirst;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_start_anim = (Button) findViewById(R.id.btn_start_anim);
iv_show_grid = (ImageView) findViewById(R.id.iv_show_grid);
btn_start_anim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
execAnimator();
}
});
iv_show_grid.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"客官点我",Toast.LENGTH_SHORT).show();
}
});
}
private int tempValue = 0;
public void execAnimator(){
ValueAnimator animator = ValueAnimator.ofInt(0,100);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
left = iv_show_grid.getLeft();
top = iv_show_grid.getTop();
iv_show_grid.layout(left+curValue-tempValue,top+curValue-tempValue,left+iv_show_grid.getWidth()+curValue-tempValue,iv_show_grid.getHeight()+curValue+top-tempValue);
tempValue = curValue;
}
});
}
}

效果:



ok,现在发现属性动画是不是能解决Tween动画的交互上的bug,imageview平移后点击是ok,

上面使用了ValueAnimator类的一个ofInt()方法,上面我们ofInt()方法传入了0,100表示从0变化到100,别以为ofInt()方法只接受2个参数,其实它是可变参数的,

public static ValueAnimator ofInt(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
return anim;
}

那我们可以利用方法实现类似上下移动的效果,

private int tempValue = 0;
public void execAnimator(){
ValueAnimator animator = ValueAnimator.ofInt(0,200,200,0,0,200,200,0,0,200,200,0);
animator.setDuration(1000);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
left = iv_show_grid.getLeft();
top = iv_show_grid.getTop();
iv_show_grid.layout(left,top+curValue-tempValue,left+iv_show_grid.getWidth(),iv_show_grid.getHeight()+curValue+top-tempValue);
tempValue = curValue;
}
});
}

效果:



是不是感觉设置了动画的重复方法,其实并没有,

还有一个ofFloat方法其实和ofInt()方法功能是一样的,只是精度不一样而已,现在再玩一个方法,就是关于颜色变化的,

public static ValueAnimator ofArgb(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
anim.setEvaluator(ArgbEvaluator.getInstance());
return anim;
}

突然这个api是要到21才能用,关键是我现在最低版本是15,算了不改了,讲下另外一个方法,也是很重要的,就是插值器,

public void setInterpolator(TimeInterpolator value) {
if (value != null) {
mInterpolator = value;
} else {
mInterpolator = new LinearInterpolator();
}
}

发现我们没有设置的时候,默认是使用LinearInterpolator,先看下TimeInterpolator这个类,

public interface TimeInterpolator {

/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation time.
*
* @param input A value between 0 and 1.0 indicating our current point
*        in the animation where 0 represents the start and 1.0 represents
*        the end
* @return The interpolation value. This value can be more than 1.0 for
*         interpolators which overshoot their targets, or less than 0 for
*         interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}

就一个方法getInterpolation()该方法一个形参input,从方法的注释上看到这个input的取值范围为[0,1],它有如下子类



我们现在可以自定义一个LinearInterpolator,通过log打印出input的值

class MyLinearInterpolator extends LinearInterpolator{
@Override
public float getInterpolation(float input) {
Log.e(TAG,"input="+input);
return super.getInterpolation(input);
}
}

设置插值器

animator.setInterpolator(new MyLinearInterpolator());

log:

07-10 09:12:10.701 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.0

07-10 09:12:10.710 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.0

07-10 09:12:10.730 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.017

07-10 09:12:10.760 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.05

07-10 09:12:10.781 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.067

07-10 09:12:10.792 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.083

07-10 09:12:10.820 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.1

07-10 09:12:10.831 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.117

07-10 09:12:10.851 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.133

07-10 09:12:10.881 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.167

07-10 09:12:10.901 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.183

07-10 09:12:10.921 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.2

07-10 09:12:10.941 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.233

07-10 09:12:10.970 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.25

07-10 09:12:10.981 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.267

07-10 09:12:11.010 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.3

07-10 09:12:11.030 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.317

07-10 09:12:11.050 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.333

07-10 09:12:11.071 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.35

07-10 09:12:11.092 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.367

07-10 09:12:11.111 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.4

07-10 09:12:11.131 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.417

07-10 09:12:11.141 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.433

07-10 09:12:11.160 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.45

07-10 09:12:11.190 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.467

07-10 09:12:11.200 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.483

07-10 09:12:11.220 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.5

07-10 09:12:11.230 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.517

07-10 09:12:11.251 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.533

07-10 09:12:11.260 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.55

07-10 09:12:11.271 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.567

07-10 09:12:11.301 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.583

07-10 09:12:11.310 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.6

07-10 09:12:11.330 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.617

07-10 09:12:11.340 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.633

07-10 09:12:11.370 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.667

07-10 09:12:11.410 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.7

07-10 09:12:11.450 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.733

07-10 09:12:11.480 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.767

07-10 09:12:11.490 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.783

07-10 09:12:11.520 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.8

07-10 09:12:11.531 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.817

07-10 09:12:11.551 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.833

07-10 09:12:11.560 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.85

07-10 09:12:11.580 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.867

07-10 09:12:11.620 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.9

07-10 09:12:11.650 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.933

07-10 09:12:11.690 3672-3672/com.example.valueanimatordemo E/MainActivity: input=0.967

07-10 09:12:11.710 3672-3672/com.example.valueanimatordemo E/MainActivity: input=1.0

通过上面的log也验证了input的取值范围是[0,1]


各个插值器的意思如下:

意义如下:
AccelerateDecelerateInterpolator   在动画开始与结束的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator                     在动画开始的地方速率改变比较慢,然后开始加速
AnticipateInterpolator                      开始的时候向后然后向前甩
AnticipateOvershootInterpolator     开始的时候向后然后向前甩一定值后返回最后的
BounceInterpolator                          动画结束的时候弹起
CycleInterpolator                             动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator                    在动画开始的地方快然后慢
LinearInterpolator                            以常量速率改变
OvershootInterpolator                      向前甩一定值后再回到原来位置

现在每个插值器都玩下,看看效果:

共同的代码如下就是设置插值器代码不同而且

AccelerateDecelerateInterpolator   



AccelerateInterpolator 



AnticipateInterpolator 



AnticipateOvershootInterpolator  



BounceInterpolator 



CycleInterpolator 



DecelerateInterpolator 



OvershootInterpolator



LinearInterpolator



现在所有的动画插值器都演示了一边,可能有的不够明显,现在讲ValueAnimator类的

public void setEvaluator(TypeEvaluator value) {} 这个函数接受的形参是TypteEvaluator,

public interface TypeEvaluator<T> {

/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction   The fraction from the starting to the ending values
* @param startValue The start value.
* @param endValue   The end value.
* @return A linear interpolation between the start and end values, given the
*         <code>fraction</code> parameter.
*/
public T evaluate(float fraction, T startValue, T endValue);

}

形参说明

fraction:从开始值startValue到endValue之间的值

startValue:开始值

endValue:结束值

现在看下TypeEvalator的一些实现类



从子类的名字就可以看出假如传入的是int值,那么就对应IntEvaluator类,

现在自定义一个IntEvaluator,看看evaluator方法中的三个参数:

/**
* 设置动画执行
*/
public void execAnimator(){
ValueAnimator animator = ValueAnimator.ofInt(0,200);
animator.setDuration(1000);
animator.setEvaluator(new MyIntEvaluator());
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
left = iv_show_grid.getLeft();
top = iv_show_grid.getTop();
iv_show_grid.layout(left,top+curValue-tempValue,left+iv_show_grid.getWidth(),iv_show_grid.getHeight()+curValue+top-tempValue);
tempValue = curValue;
}
});
}
class MyIntEvaluator extends IntEvaluator{
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
Log.e(TAG,"fraction="+fraction);
Log.e(TAG,"startValue="+fraction);
Log.e(TAG,"endValue="+endValue);
Log.e(TAG,"结果值="+super.evaluate(fraction, startValue, endValue));
return super.evaluate(fraction, startValue, endValue);
}
}

log:

07-10 14:06:53.232 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.0

07-10 14:06:53.232 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.0

07-10 14:06:53.242 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.242 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=0

07-10 14:06:53.255 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.0

07-10 14:06:53.255 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.0

07-10 14:06:53.255 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.255 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=0

07-10 14:06:53.272 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=7.1290135E-4

07-10 14:06:53.272 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=7.1290135E-4

07-10 14:06:53.272 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.282 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=0

07-10 14:06:53.305 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.0061558187

07-10 14:06:53.305 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.0061558187

07-10 14:06:53.305 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.305 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=1

07-10 14:06:53.342 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.017309189

07-10 14:06:53.342 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.017309189

07-10 14:06:53.342 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.342 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=3

07-10 14:06:53.362 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.02447176

07-10 14:06:53.362 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.02447176

07-10 14:06:53.372 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.372 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=4

07-10 14:06:53.402 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.043654233

07-10 14:06:53.402 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.043654233

07-10 14:06:53.402 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.412 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=8

07-10 14:06:53.442 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.06724939

07-10 14:06:53.442 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.06724939

07-10 14:06:53.442 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.442 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=13

07-10 14:06:53.462 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.09549156

07-10 14:06:53.462 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.09549156

07-10 14:06:53.482 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.482 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=19

07-10 14:06:53.533 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.16582394

07-10 14:06:53.533 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.16582394

07-10 14:06:53.533 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.533 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=33

07-10 14:06:53.562 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.20610732

07-10 14:06:53.562 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.20610732

07-10 14:06:53.562 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.562 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=41

07-10 14:06:53.602 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.27300477

07-10 14:06:53.602 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.27300477

07-10 14:06:53.612 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.622 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=54

07-10 14:06:53.631 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.32179415

07-10 14:06:53.631 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.32179415

07-10 14:06:53.642 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.642 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=64

07-10 14:06:53.662 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.34549147

07-10 14:06:53.662 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.34549147

07-10 14:06:53.693 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.693 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=69

07-10 14:06:53.772 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.5

07-10 14:06:53.772 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.5

07-10 14:06:53.793 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.802 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=100

07-10 14:06:53.822 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.6044678

07-10 14:06:53.832 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.6044678

07-10 14:06:53.832 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.832 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=120

07-10 14:06:53.862 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.65450853

07-10 14:06:53.862 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.65450853

07-10 14:06:53.862 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.872 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=130

07-10 14:06:53.902 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.7269952

07-10 14:06:53.932 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.7269952

07-10 14:06:53.932 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.932 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=145

07-10 14:06:53.962 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.7938927

07-10 14:06:53.972 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.7938927

07-10 14:06:53.982 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:53.992 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=158

07-10 14:06:54.022 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.8719225

07-10 14:06:54.033 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.8719225

07-10 14:06:54.033 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.033 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=174

07-10 14:06:54.062 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.9045085

07-10 14:06:54.062 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.9045085

07-10 14:06:54.062 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.062 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=180

07-10 14:06:54.072 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.91962016

07-10 14:06:54.082 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.91962016

07-10 14:06:54.082 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.093 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=183

07-10 14:06:54.134 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.9671645

07-10 14:06:54.134 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.9671645

07-10 14:06:54.142 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.142 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=193

07-10 14:06:54.175 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.98309815

07-10 14:06:54.182 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.98309815

07-10 14:06:54.192 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.212 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=196

07-10 14:06:54.222 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.9973154

07-10 14:06:54.222 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.9973154

07-10 14:06:54.232 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.232 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=199

07-10 14:06:54.252 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.9993685

07-10 14:06:54.262 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.9993685

07-10 14:06:54.262 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.272 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=199

07-10 14:06:54.292 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=1.0

07-10 14:06:54.292 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=1.0

07-10 14:06:54.292 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:06:54.322 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=200

从上面的log可以看出,endValue的值是不变的,也就是我们这行代码传入的第二个参数:

ValueAnimator animator = ValueAnimator.ofInt(0,200);

startValue的值是从0到1,fraction的值也是从0到1,这二个值其实相等的,只是fraction是float值,startValue值是int值,而结果值的计算公式为:

public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}

这是源码中已有的,我们就拿log中的一个值来计算

07-10 14:16:04.042 2128-2128/com.example.valueanimatordemo E/MainActivity: fraction=0.11175674

07-10 14:16:04.052 2128-2128/com.example.valueanimatordemo E/MainActivity: startValue=0.11175674

07-10 14:16:04.052 2128-2128/com.example.valueanimatordemo E/MainActivity: endValue=200

07-10 14:16:04.052 2128-2128/com.example.valueanimatordemo E/MainActivity: 结果值=22

0.11175674+0.11175674*(200-0.11175674)=0.11175674*(1+200-0.11175674)=22.450613055062455
但是结果是Integer,所以结果就是22了

在这补充一个知识点:

ValueAnimator
animator = ValueAnimator.ofInt(100,200); 这个100是要执行动画的起始坐标,200是动画结束时的坐标,这个是以父view的左上角为参考点,

下面我们重写evaluate()方法的返回值看看结果是什么样的:

class MyIntEvaluator extends IntEvaluator{
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int temp=(int)fraction;
int startInt= startValue;
return (int)(100+startInt + fraction * (endValue - startInt));
}
}

效果:



其实这个不看效果,也知道肯定比传入的200(最终坐标)要大,现在看一个以后会经常使用的一个类就是ArgbEvaluator,

/**
* 设置动画执行
*/
public void execAnimator(){
ValueAnimator animator = ValueAnimator.ofInt(0xffffff00,0xffffff99);
animator.setEvaluator(new ArgbEvaluator());
animator.setDuration(5000);

animator.setEvaluator(new ArgbEvaluator());
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int curValue = (int)animation.getAnimatedValue();
btn_argb.setBackgroundColor(curValue);
}
});
}

效果:



ValueAnimator类还有一个可以自定义对象的方法就是ofObject(),看源码:

public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
ValueAnimator anim = new ValueAnimator();
anim.setObjectValues(values);
anim.setEvaluator(evaluator);
return anim;
}


参数说明:

evaluator:这个是你自定义的TypeEvaluator

values:是你对这个自定义对象的值的变化

之前的博客记得写过什么水波纹类似的效果,其实就是在时间很短的情况下改变圆的半径实现的,今天也用这个也实现下这个效果

public class CustomView extends View {
private static final String TAG ="CustomView" ;
private Paint mPaint;
private MyPoint myPoint;
public CustomView(Context context) {
super(context);
}

public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
}

public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(myPoint!=null){
Log.e(TAG,"第一次他的半径是==="+myPoint.getRaduis());
canvas.drawCircle(200, 200, myPoint.getRaduis(), mPaint);
}
}
public void execAnimator() {
ValueAnimator animator = ValueAnimator.ofObject(new RadiusEvaluator(), new MyPoint(10), new MyPoint(200));
animator.setDuration(100);
animator.setRepeatCount(10);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
myPoint = (MyPoint)animation.getAnimatedValue();
invalidate();
}
});
}
}

自定义半径类:

public class MyPoint {

private int raduis;

public MyPoint(int raduis) {
this.raduis = raduis;
}

public int getRaduis() {
return raduis;
}
public void setRaduis(int raduis) {
this.raduis = raduis;
}
}

自定义TypeEaluator

public class RadiusEvaluator implements TypeEvaluator<MyPoint> {
@Override
public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) {
int startRaduis = startValue.getRaduis();
int endRaduis  = endValue.getRaduis();
int curValue = (int)(startRaduis + fraction * (endRaduis - startRaduis));
return new MyPoint(curValue);
}
}

最后就是按钮点击执行动画了

btn_start_anim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
customview.execAnimator();
}
});

效果:



现在我向动画中添加一个插值器BounceInterpolator,这个表示动画结束的时候弹起,而且要把动画时间放长点才好看出来效果:

public void execAnimator() {
ValueAnimator animator = ValueAnimator.ofObject(new RadiusEvaluator(), new MyPoint(10), new MyPoint(100));
animator.setDuration(1000);
animator.setInterpolator(new BounceInterpolator());
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
myPoint = (MyPoint)animation.getAnimatedValue();
invalidate();
}
});
}

效果:



ValueAnimator类基本的使用都讲完了,你发现使用ValueAnimator做view平移的时候是用view的layout()方法实现的,而ValueAnimator类并没有给我们直接提供方法让我们自己调用,那么就引人了ObjectAnimator这个类了,

ObjectAnimator是继承自ValueAnimator,所以ObjectAnimator类中的方法很多是继承了ValueAnimator中的方法,但是也对一些方法做了重写,比如ofInt()方法:

ValueAnimator类的ofInt()方法源码:

public static ValueAnimator ofInt(int... values) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(values);
return anim;
}

ObjectAnimator中的ofInt()方法

public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setIntValues(values);
return anim;
}

从源码就明显看的出来ofInt()方法不同,现在解释下ObjectAnimator类的ofInt()方法

public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {}

参数说明:

Object target:作用于那个view,这个target就是那个view对象

String propertyName:作用于view上那个属性,

int...values:可变参数,也就是要对第二个参数(view属性)进行动画时传递的值

这三个参数中第一个和第三个参数都好理解,那么第二个参数是view的属性名是指啥,进入到View的源码中找出这几个函数:

public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {}

public void setRotation(float rotation) {}

public void setRotationX(float rotationX) {}

public void setRotationY(float rotationY) {}

public void setTranslationX(float translationX) {}

public void setTranslationY(float translationY) {}

public void setTranslationZ(float translationZ) {}

public void setScaleX(float scaleX) {}

public void setScaleY(float scaleY) {}

上面是View中的关于动画的几个set方法,我们看出来set函数都有一个形参,而ObjectAnimator中的ofInt()方法中第二个参数propertyName就是上面几个set函数中的形参,比如rotationX,translationX,scaleX,alpha,现在每个函数做一个简单的演示:

setAlpha():

public class MainActivity extends AppCompatActivity {
private Button btn_start_anim;
private TextView tv_show_anim;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_show_anim = (TextView) findViewById(R.id.tv_show_anim);
btn_start_anim = (Button) findViewById(R.id.btn_start_anim);
btn_start_anim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
execAnimator();
}
});
}
public void execAnimator(){
ObjectAnimator objectAnimator =  ObjectAnimator.ofFloat(tv_show_anim,"alpha",0,1,1,0,0,1,1,0);
objectAnimator.setDuration(2000);
objectAnimator.start();
}
}

效果:



setScaleX()

public void execAnimator(){
ObjectAnimator objectAnimator =  ObjectAnimator.ofFloat(tv_show_anim,"scaleX",1,3);
objectAnimator.setDuration(200);
objectAnimator.start();
}

效果:



setTranslationY()

public void execAnimator(){
ObjectAnimator objectAnimator =  ObjectAnimator.ofFloat(tv_show_anim,"translationY",0,300);
objectAnimator.setDuration(200);
objectAnimator.start();
}

效果:



setRotationX()

public void execAnimator(){
ObjectAnimator objectAnimator =  ObjectAnimator.ofFloat(tv_show_anim,"rotationX",0,180,180,0,0,180);
objectAnimator.setDuration(2000); objectAnimator.start();}
效果:



在这要讲一个可能会被忽略的问题就是我们每个view都有的一个方法就是设置背景

public void setBackgroundColor(@ColorInt int color){} 发现它接受的是一个int形参,如果要对这个属性进行动画的话,是不是属性名字就为color呢?答案是错的,属性名是:BackgroundColor

public void execAnimator(){
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(tv_show_anim, "BackgroundColor", 0xffffffff, 0xffffff00, 0xff00ffff);
objectAnimator.setDuration(5000); objectAnimator.setRepeatCount(5); objectAnimator.setEvaluator(new ArgbEvaluator()); objectAnimator.start();}
效果:



前面都是单独的一个动画,如果我想实现一个放大并且同时有透明度的动画,ObjectValueAnimator和ValueAnimator都没办法实现我这需求,针对这个问题google一些大神们已经帮我们想办法解决了,Google帮我们提供了AnimatorSet,这个类有2个重要的函数:

public void playTogether(Animator... items) {}

public void playSequentially(Animator... items) {}

上面二个方法可以从后一个单词中可以看的出来,together是一起的意思,sequence是顺序的意思,Sequentially是副词吧,表示按顺序
所以这二个方法意思就出来了


playTogether中的形参是一个可变参数,传递的是动画的父类,这就是所谓的多态,当然AnimatorSet还给我们提供了重载的方法就是传入的是动画集合,




现在写个例子

布局文件:



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/btn_start_anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="执行动画"
/>
<Button
android:id="@+id/button1"
android:layout_width="70dp"
android:layout_height="35dp"
android:text="按钮1"
android:layout_marginTop="40dp"
android:background="#FFBBFF"
/>
<Button
android:id="@+id/button2"
android:layout_width="70dp"
android:layout_height="35dp"
android:text="按钮2"
android:layout_marginTop="40dp"
android:layout_toRightOf="@id/button1"
android:layout_marginLeft="10dp"
android:layout_alignParentBottom="true"
android:background="#FF8247"
/>
<Button
android:id="@+id/button3"
android:layout_width="70dp"
android:layout_height="35dp"
android:text="按钮3"
android:layout_marginTop="40dp"
android:layout_toRightOf="@id/button2"
android:layout_marginLeft="10dp"
android:background="#CD2990"
/>
</RelativeLayout>


MainActivity类



public class MainActivity extends AppCompatActivity {
private Button btn_start_anim,button1,button2,button3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

btn_start_anim = (Button) findViewById(R.id.btn_start_anim);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);

btn_start_anim.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
execAnimator();
}
});

}
private void execAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(button1, "translationY",60,400);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(button2, "translationY", 0, -400);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(button3, "translationY", 60, 400);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3);
animatorSet.setDuration(2000);
animatorSet.start();
}
}

效果:






从这效果中可以看出来AnimatorSet中的playSequentially()方法是按顺序(往AnimatorSet中添加的顺序)执行动画的,前一个动画执行完后,才播放下一个动画,现在我把playSequentially()改成playTogether()方法,看看效果:






很明显这三个动画是同时执行的,现在我需要实现一个可以循环执行的动画需求,但是你发现AnimatorSet中并没有给我们提供这种方法,那么自己能不能实现呢?
YES


private void execAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(button1, "translationY",60,400);
objectAnimator1.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(button2, "translationY", 0, -400);
objectAnimator2.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(button3, "translationY", 60, 400);
objectAnimator3.setRepeatCount(ValueAnimator.INFINITE);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1,objectAnimator2,objectAnimator3);
animatorSet.setDuration(2000);
animatorSet.start();
}

效果:



再来玩一个动画就下班

private void execAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(iv_ball, "translationY",0,590);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(iv_ball, "translationX", 0, 380);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(iv_ball, "translationY", 590, 0);
ObjectAnimator objectAnimator4 = ObjectAnimator.ofFloat(iv_ball, "translationX", 380, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3,objectAnimator4);
animatorSet.setDuration(2000);
animatorSet.start();
}

这个x,y轴的值是我估测的,没有通过计算,懒的写!效果



现在有个问题就是AnimatorSet中有setDuration()方法,而单独的ObjectAnimator也有setDuration()设置动画执行的方法,那么最后以那个为标准呢?我写了例子演示下就知道了

public void execAnimator() {
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(button1, "translationY",0,600);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(button2, "translationY", 0, 600);
objectAnimator1.setDuration(1000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator1,objectAnimator2);
animatorSet.setDuration(10000);
animatorSet.start();
}
效果:



从效果上看就知道最后是以AnimatorSet设置的时间为准,

总结:在设置多个动画一起执行的时候,最后以AnimatorSet设置的时间为标准
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: