前面关于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这个类了,