对值进行了一个平滑的动画过渡;我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果
方法 | 使用 |
---|---|
ofFloat(float… values) 构建ValueAnimator的实例,方法当中允许传入多个float类型的参数 | 例:将一个值从0平滑过渡到1或 从0过渡到5,再过渡到3,再过渡到10 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f); |
ofInt(int… values) 构建ValueAnimator的实例,方法当中允许传入多个Int类型的参数 | 例:将一个值从0平滑过渡到1或 从0过渡到5,再过渡到3,再过渡到10 ValueAnimator anim = ValueAnimator.ofInt(0, 1); ValueAnimator anim = ValueAnimator.ofInt(0, 5, 3, 10); |
ofObject(TypeEvaluator evaluator, Object… values) 构建ValueAnimator的实例,用于对任意对象进行动画操作 | evaluator:数值具体变化过程的当前数值,是一个自定义的 Evaluator values:指定动画变化区间,类比参考ofInt()、ofFloat() 例: 1. 先定义个Point类 public class Point { private float x; private float y; public Point(float x, float y){ this.x = x; this.y = y; } public float getX() { return x; } public float getY(){ return y; } } 2. 再定义PointEvaluator 类实现TypeEvaluator的接口再使用 public class PointEvaluator implements TypeEvaluator { @Override public Character evaluate(float fraction, Character startValue, Character endValue) { //将startValue和endValue强转成Point对象 Point start = (Point) startValue; Point end = (Point) endValue; //当前值 = 初始值 + fraction * (结束值 - 初始值) float x = start.getX() + fraction * (end.getX() - start.getX()); float y = start.getY() + fraction * (end.getY() - start.getY()); //组装一个新的Point对象当中并返回 Point point = new Point(x,y); return point; } } 3. 使用 Point point1 = new Point(0, 0); Point point2 = new Point(300, 300); ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2); |
setDuration() 设置动画运行的时长,单位毫秒 | 例:设置动画时长600毫秒 anim.setDuration(600); |
start() 启动动画 | 例:anim.start(); |
setStartDelay() 设置动画延迟播放的时间,单位毫秒 | |
setRepeatCount() 设置动画循环播放的次数 | |
setRepeatMode() 设置动画循环播放的模式 | 2种模式如下: 1.RESTART重新播放 2.REVERSE倒序播放 |
ValueAnimator类工作流程如下
ofInt(0, 100)--------------------------->加速器--------------------------->Evaluator--------------------------->监听器返回
动画运行的值区间 当前值区间的值 计算当前进度的数值 在AnimatorUpdateListener中返回
可以对任意对象的任意属性进行动画操作;ObjectAnimator类是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的.ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法
构造方法如下:
public static ObjectAnimator ofFloat(Object target, String propertyName, float… values)
public static ObjectAnimator ofInt(Object target, String propertyName, float… values)
target: 指定执行动画的控件
propertyName: 指定控件的属性
values: 可变长参数
例:
//透明度动画
ObjectAnimator animator = ObjectAnimator.ofFloat(view,"alpha",1,0,1);
animator.setDuration(2000);
animator.start();
//旋转动画:围绕x轴旋转
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationX",0,270,0);
animator.setDuration(2000);
animator.start();
//旋转动画:围绕y轴旋转
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotationY",0,180,0);
animator.setDuration(2000);
animator.start();
//旋转动画:围绕z轴旋转
ObjectAnimator animator = ObjectAnimator.ofFloat(tv,"rotation",0,270,0);
animator.setDuration(2000);
animator.start();
//平移动画:在x轴上平移
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationX", 0, 200, -200,0);
animator.setDuration(2000);
animator.start();
//平移动画:在y轴上平移
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "translationY", 0, 200, -100,0);
animator.setDuration(2000);
animator.start();
//缩放动画:在x轴缩放
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleX", 0, 3, 1);
animator.setDuration(2000);
animator.start();
//缩放动画:在y轴上缩放
ObjectAnimator animator = ObjectAnimator.ofFloat(tv, "scaleY", 0, 3, 1);
animator.setDuration(2000);
animator.start();
ObjectAnimator类工作流程如下
ofFloat(tv, “scaleX”, 0, 3, 1)--------------------------->加速器--------------------------->Evaluator--------------------------->调用set函数
定义动画对象和区间 当前值区间的值 计算当前进度的数值 使用set函数完成动画
实现组合动画功能
方法 | 使用 |
---|---|
play(Animator anim) 返回一个AnimatorSet.Builder的实例能够控制动画的执行顺序和相互之间的依赖。 | 例: 同下 |
after(Animator anim) 将现有动画插入到传入的动画之后执行 | 例: ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, “backgroundColor”, Color.WHITE, Color.GREEN); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, “scaleX”, 0.1f, 1.2f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, “scaleY”, 0.5f, 1.0f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(objectAnimator1).after(objectAnimator2); animatorSet.setDuration(3000); animatorSet.start(); |
after(long delay) 将现有动画延迟指定毫秒后执行 | 例: ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, “backgroundColor”, Color.WHITE, Color.GREEN); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, “scaleX”, 0.1f, 1.2f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, “scaleY”, 0.5f, 1.0f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(objectAnimator1).after(objectAnimator2).after(10000); animatorSet.setDuration(3000); animatorSet.start(); |
before(Animator anim) 将现有动画插入到传入的动画之前执行 | 例: ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, “backgroundColor”, Color.WHITE, Color.GREEN); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, “scaleX”, 0.1f, 1.2f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, “scaleY”, 0.5f, 1.0f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(objectAnimator1).before(objectAnimator2); animatorSet.setDuration(3000); animatorSet.start(); |
with(Animator anim) 将现有动画和传入的动画同时执行 | 例: ObjectAnimator objectAnimator1 = ObjectAnimator.ofArgb(mTextView, “backgroundColor”, Color.WHITE, Color.GREEN); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(mTextView, “scaleX”, 0.1f, 1.2f); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(mTextView, “scaleY”, 0.5f, 1.0f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(objectAnimator1).with(objectAnimator7).with(objectAnimator11); animatorSet.setDuration(3000); animatorSet.start(); |
Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。ObjectAnimator是继承自ValueAnimator的,而ValueAnimator又是继承自Animator的,AnimatorSet也是继承自Animator的;因此都是可以使用addListener()这个方法的
例:添加一个监听器的代码如下所示:
anim.addListener(new AnimatorListener() {
@Override
// onAnimationStart()方法会在动画开始的时候调用
public void onAnimationStart(Animator animation) {
}
@Override
// onAnimationRepeat()方法会在动画重复执行的时候调用
public void onAnimationRepeat(Animator animation) {
}
@Override
// onAnimationEnd()方法会在动画结束的时候调用
public void onAnimationEnd(Animator animation) {
}
@Override
// onAnimationCancel()方法会在动画被取消的时候调用
public void onAnimationCancel(Animator animation) {
}
});
使用这个类就可以解决掉实现接口繁琐的问题了;向addListener()方法中传入这个适配器对象,由于AnimatorListenerAdapter中已经将每个接口都实现好了,所以只需要单独重写这一个方法就可以了
例:
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
}
通过XML来编写动画可能会比通过代码来编写动画要慢一些,但是在重用方面将会变得非常轻松,比如某个将通用的动画编写到XML里面,我们就可以在各个界面当中轻松去重用它。具体做法是在res目录下面新建一个animator文件夹,所有属性动画的XML文件都应该存放在这个文件夹当中
XML标签与代码的对照表:
XML标签 | 程序代码 |
---|---|
animator | ValueAnimator |
objectAnimator | ObjectAnimator |
set | AnimatorSet |
例:实现一个从0到100平滑过渡的动画,在XML当中就可以这样写:
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0"
android:valueTo="100"
android:valueType="intType"/>
例:如果我们想将一个视图的alpha属性从1变成0,就可以这样写:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType"
android:propertyName="alpha"/>
例:将一个视图先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作,就可以这样写:
<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially" >
<objectAnimator
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>
<set android:ordering="together" >
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
</objectAnimator>
<set android:ordering="sequentially" >
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" >
</objectAnimator>
</set>
</set>
</set>
加载XML动画
1. 调用AnimatorInflater的loadAnimator将XML动画文件加载
2. 调用setTarget()方法将这个动画设置到某一个对象上
3. 调用start()方法启动动画
例:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
自带TimeInterpolator
TimeInterpolator接口已经有非常多的实现类了,这些都是Android系统内置好的并且我们可以直接使用的Interpolator。每个Interpolator都有它各自的实现效果
取值 | 说明 |
---|---|
AccelerateDecelerateInterpolator | 先加速后减速效果的Interpolator(默认) |
AccelerateInterpolator | 加速运动效果的Interpolator |
AnticipateInterpolator | 预计效果的Interpolator |
AnticipateOvershootInterpolator | 预测过度的Interpolator |
BounceInterpolator | 反弹效果的Interpolator |
CycleInterpolator | 循环效果的Interpolator |
DecelerateInterpolator | 减速运动效果的Interpolator |
LinearInterpolator | 线性效果的Interpolator |
OvershootInterpolator | 过度效果的Interpolator |
PathInterpolator | 路径效果的Interpolator |
系统中TimeInterpolator的接口定义如下:
public interface TimeInterpolator {
float getInterpolation(float input);
}
自定义TimeInterpolator
getInterpolation()方法中接收一个input参数,这个参数的值会随着动画的运行而不断变化,不过它的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是0到1。也就是说当动画一开始的时候input的值是0,到动画结束的时候input的值是1,而中间的值则是随着动画运行的时长在0到1之间变化的。input的值决定了fraction的值。input的值是由系统经过计算后传入到getInterpolation()方法中的,然后我们可以自己实现getInterpolation()方法中的算法,根据input的值来计算出一个返回值,而这个返回值就是fraction
例:自定义TimeInterpolator的使用
public class PointEvaluator implements TypeEvaluator { // 实现TypeEvaluator接口
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) { //重写了evaluate()方法
//将startValue和endValue强转成Point对象
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
//根据fraction来计算当前动画的x和y的值
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
//组装到一个新的Point对象当中并返回
Point point = new Point(x, y);
return point;
}
}
public class DecelerateAccelerateInterpolator implements TimeInterpolator{ //实现TimeInterpolator接口
@Override
public float getInterpolation(float input) { //getInterpolation()方法中的逻辑算法实现
float result;
if (input <= 0.5) {
result = (float) (Math.sin(Math.PI * input)) / 2;
} else {
result = (float) (2 - Math.sin(Math.PI * input)) / 2;
}
return result;
}
}
代码中使用
private void startAnimation() {
Point startPoint = new Point(getWidth() / 2, RADIUS);
Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setInterpolator(new DecelerateAccelerateInterpolator()); //使用定义的DecelerateAccelerateInterpolator类
anim.setDuration(3000);
anim.start();
}
TimeInterpolator为View的动画操作提供一种更加便捷的人性化用法,便于更加容易理解
animate()方法:是在Android 3.1系统上新增的一个方法,这个方法的返回值是一个ViewPropertyAnimator对象,也就是说拿到
这个对象之后我们就可以调用它的各种方法来实现动画效果了;ViewPropertyAnimator是支持连缀用法的,将所
有想要组合的动画通过这种连缀的式拼接起来,这样全部动画就都会一起被执行;
等到所有在ViewPropertyAnimator上设置的方法都执行完毕后,动画就会自动启动。当然如果不想使用这一默认
机制的话,我们也可以显式地调用start()方法来启动动画
例:TextView从常规状态变成透明状态
textview.animate().alpha(0f);
//之前是这样的
// ObjectAnimator animator = ObjectAnimator.ofFloat(textview, “alpha”, 0f);
//animator.start();
例:textview运动到500,500这个坐标点上
textview.animate().x(500).y(500);
例:textview运动到500,500这个坐标点上,运行5秒钟
textview.animate().x(500).y(500).setDuration(5000);
例:textview运动到500,500这个坐标点上,运行5秒钟并使用补间器
textview.animate().x(500).y(500).setDuration(5000).setInterpolator(new BounceInterpolator());