一、概述
- 属性动画(Property Animation)是在 Android 3.0(API 11)后才提供的一种全新动画模式
- 属性动画的出现主要是为了弥补补间动画(Tween Animation)的缺陷
- 下面来看一下补间动画的缺陷
1、 作用对象的局限
只能够作用在视图View上,即只可以对一个Button、TextView、甚至是LinearLayout,或者其它继承自View的组件进行动画操作,但无法对非View的对象进行动画操作2、 没有改变View的属性,只是改变视觉效果
只在屏幕绘制上的动画,控件的属性并没有改变,一个经典的问题就是一个Button从一个地方移动到另一个地方,点击事件还是在原来的地方3、拓展性太差
只能写移动、缩放、旋转、渐变四种动画,以及这四种动画的组合,一旦遇到相对复杂的动画效果,即超出了上述4种动画效果,那么补间动画则无法实现
二、特点
- 可以用在任意java对象
- 不只是4种基本变换,还有其他动画效果,并且可以自定义动画效果
三、工作原理
- 在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果,注意看这里,属性动画的本质不再是强调动画本身了,而是变成了数值发生器,不管你想干什么,属性动画只关心生成数值数列给你去使用,这就是属性动画拓展性的根本,只关心数值的生成
-
具体的工作原理如下图
微信图片_20180918145035.png
从以上的图片原理分析有三个核心类非常重要:AnimatorSet ValueAnimator ObjectAnimator
- AnimatorSet 属性动画集合,就是把一堆动画放在一起执行,属性动画的集合提供了几种非常灵活的动画执行方式。
- ValueAnimator 属性动画的核心:数值发生器,生成数值序列的类
- ObjectAnimator 是ValueAnimator的子类,是对ValueAnimator操作的封装,使用起来更简便,一般都是用来对某一个对象的属性做动画的。
四、 ValueAnimator
ValueAnimator 是属性动画的根基了,是应用最广广泛的了,尤其是在自定义 view 中,ValueAnimator类中有几个核心的方法
- ValueAnimator ofInt (int... values):返回一个int型变化的ValueAnimator
(采用默认的整型估值器(IntEvaluator)) - ValueAnimator ofFloat (float... values):返回一个float型变化的ValueAnimator
(采用默认的浮点型估值器 (FloatEvaluator)) - ValueAnimator ofArgb (int... values):返回一个颜色值变化的ValueAnimator,API LEVEL 21引入。
(采用默认的颜色估值器 (ArgbEvaluator)
以上三个构造方法如果传入了3个参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,以此类推 - ValueAnimator ofObject (TypeEvaluator evaluator, Object... values):返回一个object型变化的ValueAnimator。
(采用自定义对象估值器 (TypeEvaluator))
从以上方法的定义上看,主要区别是四种不同类型的估值器达到返回不同效果的数值
还是老一套,先看使用方法和效果, 使用的方式 分为 XML 设置 / Java 代码设置
4-1、ValueAnimator ofInt (int... values)
方式一、java代码设置
//设置动画的初始值和结束值
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 5);
//设置动画的时间
valueAnimator.setDuration(500);
//设置延时播放
valueAnimator.setStartDelay(500);
//设置动画播放重复次数,ValueAnimator.INFINITE=无限重复
valueAnimator.setRepeatCount(0);
//设置动画播放模式 ValueAnimator.RESTART=正序播放 ValueAnimator.REVERSE=倒叙播放
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
//将改变的值手动付给对象的属性值:通过动画的更新监听器实现
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
Log.d("DXDD", animatedValue + "");
}
});
valueAnimator.start();
效果图
微信图片_20180918164044.png从上面可以看出数值是从0-5的变化,可以看出并不是均匀分布,,这就和插值器有关系了,,看下面源码
// The time interpolator to be used if none is set on the animation
private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
通过源码看出插值器的速率是始末速率较慢,中间加速,如果需要改变动画速率可以通过改变插值器的方法进行。从上可以看出插值器和估值器的联系。看下图分析
微信图片_20180918180239.png
方式二、xml代码设置
- 步骤1:在路径 res/animator的文件夹里创建相应的动画 .xml文件
- 步骤2:设置动画参数
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:valueFrom="0"
android:valueTo="5"
android:valueType="intType"
android:duration="500"
android:startOffset="500"
android:repeatCount="0"
android:repeatMode="restart"
android:fillBefore="true"
android:interpolator="@android:anim/overshoot_interpolator"
/>
- 使用方法
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(PropertyAnimaActivity.this, R.animator.values_int);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
Log.d("DXDD", animatedValue + "");
}
});
animator.start();
效果图同上,下面结合手动赋值给对象属性做个实例看看效果
- 实现的动画效果:图片宽高放大一倍
//设置动画的初始值和结束值(图片宽度放大一倍)
ValueAnimator valueAnimator = ValueAnimator.ofInt(img_girl.getLayoutParams().width, img_girl.getLayoutParams().width * 2);
//设置动画的时间
valueAnimator.setDuration(1000);
//设置动画播放重复次数,ValueAnimator.INFINITE=无限重复
valueAnimator.setRepeatCount(0);
//设置动画播放模式 ValueAnimator.RESTART=正序播放 ValueAnimator.REVERSE=倒叙播放
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
//设置插值器
valueAnimator.setInterpolator(new LinearInterpolator());
//将改变的值手动付给对象的属性值:通过动画的更新监听器实现
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 每次值变化时,将值手动赋值给对象的属性
img_girl.getLayoutParams().width = (int) animation.getAnimatedValue();
//刷新视图,即重新绘制,实现动画效果
img_girl.requestLayout();
}
});
valueAnimator.start();
//设置动画的初始值和结束值(图片高度放大一倍)
ValueAnimator valueAnimator = ValueAnimator.ofInt(img_girl.getLayoutParams().height, img_girl.getLayoutParams().height * 2);
//设置动画的时间
valueAnimator.setDuration(1000);
//设置动画播放重复次数,ValueAnimator.INFINITE=无限重复
valueAnimator.setRepeatCount(2);
//设置动画播放模式 ValueAnimator.RESTART=正序播放 ValueAnimator.REVERSE=倒叙播放
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
//设置插值器
valueAnimator.setInterpolator(new LinearInterpolator());
//将改变的值手动付给对象的属性值:通过动画的更新监听器实现
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 每次值变化时,将值手动赋值给对象的属性
img_girl.getLayoutParams().height = (int) animation.getAnimatedValue();
//刷新视图,即重新绘制,实现动画效果
img_girl.requestLayout();
}
});
valueAnimator.start();
效果图
girl.gif合并是两种动画同事播放,,感觉代码有点重复使用吧,,学习完下面的内容会有更简单的实现方法
4-2、ValueAnimator ofFloat (float... values)使用方法和效果同上,不同的地方是监听返回值是float类型,返回的类型不同主要是因为使用了不同的估值器(估值器在下面会详细介绍)
4-3、ValueAnimator ofArgb (int... values)
ValueAnimator中的ofArgb()可以帮助我们实现颜色的渐变效果,Google在API LEVEL 21之后增加了这个方法ofArgb()。通过这个方法我们更容易地实现颜色演变,通过ofArgb和ArgbEvaluator,我们可以轻松实现颜色渐变效果
java代码
//第一种方法
//设置初始值过度值和结束值
ValueAnimator argbAnim = ValueAnimator.ofArgb(Color.parseColor("#ff669900"), Color.parseColor("#ff0099cc"), Color.parseColor("#ffff4444"), Color.parseColor("#ff669900"));
//设置动画时间
argbAnim.setDuration(2000);
//设置匀速插值器
argbAnim.setInterpolator(new LinearInterpolator());
//动画监听
argbAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
btn_Argb.setBackgroundColor((Integer) animation.getAnimatedValue());
}
});
argbAnim.start();
//第二种方法
//设置初始值过度值和结束值
ValueAnimator argbAnim = ValueAnimator.ofInt(Color.parseColor("#ff669900"), Color.parseColor("#ff0099cc"), Color.parseColor("#ffff4444"), Color.parseColor("#ff669900"));
//设置动画时间
argbAnim.setDuration(2000);
//设置估值器
argbAnim.setEvaluator(new ArgbEvaluator());
//设置匀速插值器
argbAnim.setInterpolator(new LinearInterpolator());
//动画监听
argbAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
btn_Argb.setBackgroundColor((Integer) animation.getAnimatedValue());
}
});
argbAnim.start();
效果图如下:(需要向下兼容用第二张方法即可实现)
argb.gif4-4、ValueAnimator ofObject (TypeEvaluator evaluator, Object... values)
ofObject方法是什么意思呢?我们都知道ofInt和ofFloat都是针对Int值和Float值的变化,但是,我们只能控制一个值的变化,但是当我们需要实现多值变化时,它们就不再满足我们的需求。因为两个属性的初始值和结束值不一样,那么我们就可以将两个属性值封装到一个对象里面,那么初始值的object和结束值的object就可以包含两个属性不同的初始值和结束值了,这个时候就需要自定义估值TypeEvaluator器达到效果。介绍完估值器在进行ValueAnimator ofObject示例练习
五、估值器 (TypeEvaluator)
- 定义:一个接口
- 作用:设置 属性值 从初始值过渡到结束值 的变化具体数值
- 应用场景: 协助插值器 实现非线性运动的动画效果
- 计算方式:根据 插值器计算出当前属性值改变的百分比 & 初始值 & 结束值 来计算 当前属性具体的数值
(如:动画进行了50%(初始值=100,结束值=200 ),那么匀速插值器计算出了当前属性值改变的百分比是50%,估值器则负责计算当前属性值 = 100 + (200-100)x50% = 150.)=初始值+动画百分比*(结束值-初始值)
系统默认提供了四种估值器,如果达不到要求那么就需要我们自定义估值器,需要自定义估值器就需要实现TypeEvaluator接口,复写evaluate()
public interface TypeEvaluator<T> {
/**
*
* @param fraction 插值器getInterpolation()的返回值
* @param startValue 起始值.
* @param endValue 结束值.
* @return T 赋给动画属性的具体数值
*
*/
public T evaluate(float fraction, T startValue, T endValue);
前面介绍过插值器与估值器的关系,其实就事插值器中input 和 fraction关系:input的值决定了fraction的值:input值经过计算后传入到插值器的getInterpolation(),然后通过实现getInterpolation()中的逻辑算法,根据input值来计算出一个返回值,而这个返回值就是fraction,那么先来看一个系统的插值器:浮点型插值器:FloatEvaluator
public class FloatEvaluator implements TypeEvaluator<Number> {
// FloatEvaluator实现了TypeEvaluator接口
// 重写evaluate()
public Float evaluate(float fraction, Number startValue, Number endValue) {
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
//计算方式:初始值+动画百分比*(结束值-初始值)
}
- 系统默认的估值器都有对应的计算逻辑,但对于ValueAnimator.ofObject(),并没有系统默认实现,因为对对象的动画操作复杂 & 多样,系统无法知道如何从初始对象过度到结束对象,因此我们需自定义估值器(TypeEvaluator)来告知系统如何进行从 初始对象 过渡到 结束对象的逻辑。下面示例实现一个加入购物车效果的估值器:
效果图
buy.gif- 如果需要达到抛物线效果,就需要自定义贝塞尔曲线数值变化的估值器
public class PointBezierTypeEvaluator implements TypeEvaluator<PointF> {
PointF control;
PointF mPointF = new PointF();
public PointBezierTypeEvaluator(PointF control) {
this.control = control;
}
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
return getBezierPoint(startValue, endValue, control, fraction);
}
/**
* 二次贝塞尔曲线公式
*
* @param start 開始的数据点
* @param end 结束的数据点
* @param control 控制点
* @param t float 0-1
* @return 不同t相应的PointF
*/
private PointF getBezierPoint(PointF start, PointF end, PointF control, float t) {
mPointF.x = (1 - t) * (1 - t) * start.x + 2 * t * (1 - t) * control.x + t * t * end.x;
mPointF.y = (1 - t) * (1 - t) * start.y + 2 * t * (1 - t) * control.y + t * t * end.y;
return mPointF;
}
- java实现方式
private void clickView(View view) {
int[] clickCoordinate = new int[2];
int[] parentCoordinate = new int[2];
int[] buyCoordinate = new int[2];
//分别获取被点击view、父布局、购物车在屏幕上的坐标
view.getLocationOnScreen(clickCoordinate);
shopping_container.getLocationOnScreen(parentCoordinate);
img_buy.getLocationOnScreen(buyCoordinate);
//创建滑动的imageview并添加到父布局中
if (moveImg == null) {
moveImg = new ImageView(this);
moveImg.setImageResource(R.drawable.red_ball);
shopping_container.addView(moveImg);
}
moveImg.setVisibility(View.VISIBLE);
moveImg.setX(clickCoordinate[0] - parentCoordinate[0]);
moveImg.setY(clickCoordinate[1] - parentCoordinate[1]);
//计算滑动imageview的三个控制点(起点、结束点、控制点)
PointF startP = new PointF();
PointF endP = new PointF();
PointF controlP = new PointF();
startP.x = clickCoordinate[0] - parentCoordinate[0];
startP.y = clickCoordinate[1] - parentCoordinate[1];
endP.x = buyCoordinate[0] - parentCoordinate[0] + img_buy.getLayoutParams().width / 5;
endP.y = buyCoordinate[1] - parentCoordinate[1] + img_buy.getLayoutParams().width / 5;
controlP.x = endP.x;
controlP.y = startP.y;
//执行动画
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointBezierTypeEvaluator(controlP), startP, endP);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF pointF = (PointF) animation.getAnimatedValue();
moveImg.setY(pointF.y);
moveImg.setX(pointF.x);
}
}
);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
moveImg.setVisibility(View.INVISIBLE);
++count;
tv_num.setText(count + "");
ScaleImage(img_buy);
}
});
valueAnimator.start();
}
- 购物车动画效果
private void ScaleImage(ImageView img) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img, "scaleX", 1f, 0.5f, 1f);
objectAnimator.setDuration(500);
objectAnimator.setInterpolator(new SpringInterpolator());
objectAnimator.start();
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(img, "scaleY", 1f, 0.5f, 1f);
objectAnimator1.setDuration(500);
objectAnimator1.setInterpolator(new SpringInterpolator());
objectAnimator1.start();
}
- 以上就是自定义估值器结合ValueAnimator.ofObject()实现购物车抛物线效果
- 从购物车动画效果代码看出 ObjectAnimator这个类的动画实现方式,下面详细介绍一下这个类
六、ObjectAnimator
上面说了ObjectAnimator是ValueAnimator的子类,是对ValueAnimator操作的封装,目的就是让我们的属性动画操作更加简单,这符合 java 简单化的思想,大伙仔细想想,简单好用就是我们码代码的终极追求之一啊,下面来看看常用属性和用法:
6-1 常用的propertyName:
- rotationX 围绕x轴旋转
- rotationY 围绕y轴旋转
- rotation 围绕轴点旋转
- translationX 在x轴方向上平移
- translationY 在y轴方向上平移
- scaleX 在x轴方向缩放
- scaleY 在y轴方向缩放
- alpha 透明度
- width 宽度
- height 高度
6-2 使用方法:
ObjectAnimator animator = ObjectAnimator.ofFloat(testView, "translationX", 100);
animator.setDuration(600);
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.setRepeatCount(1);
animator.start();
- 这是一个位移动画,像右移动100px,需要达到其他的效果,方法同上,只需修改动画属性即可。
七、path动画
5.0版本属性动画中添加了一个path动画,可以让 view 沿着 path 的路径做动画
- 代码
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, View.X, View.Y, path_view.getPath());
animator.setDuration(1000);
animator.setRepeatMode(ObjectAnimator.REVERSE);
animator.setRepeatCount(1);
animator.start();
- 有4个参数,第一个是目标 view,后面2个是需要操作的 view 的位置坐标,最后是 path
-
效果图
path.gif
八、AnimatorSet 动画集合
8-1在AnimatorSet中给为我们提供了两个方法playSequentially和playTogether
- playSequentially表示所有动画依次播放
- playTogether表示所有动画一起开始
playTogether和playSequentially在激活动画后,控件的动画情况与它们无关,它们只负责定时激活控件动画。 playSequentially只有上一个控件做完动画以后,才会激活下一个控件的动画,如果上一控件的动画是无限循环,那下一个控件就无法做动画了。 - 使用示例:
ObjectAnimator objectAnimator01 = ObjectAnimator.ofArgb(ivImage05, "BackgroundColor",
getResources().getColor(R.color.colorPrimary),
getResources().getColor(R.color.colorAccent),
getResources().getColor(R.color.colorPrimary));
ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage05, "TranslationY", 0, 300, 0);
ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage06, "TranslationY", 0, 400, 0);
ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage07, "TranslationY", 0, 500, 0);
ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage08, "TranslationY", 0, 600, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(objectAnimator01, objectAnimator02, objectAnimator03, objectAnimator04, objectAnimator05);
animatorSet.setDuration(2000);
animatorSet.start();
8-2 AnimatorSet.Builder(自由设置动画顺序)
AnimatorSet.Builder用于实现playTogether和playSequentially无法实现的效果,可以实现非常自由的组合动画,比如有三个动画A,B,C想先播放C然后同时播放A和B,利用playTogether和playSequentially是没办法实现的,但利用AnimatorSet.Builder却可以轻易实现。
AnimatorSet.Builder常用方法:
方法 | 说明 |
---|---|
public Builder play(Animator anim) | 表示要播放哪个动画 AnimatorSet中的play方法是获取AnimatorSet.Builder对象的唯一途径 |
public Builder with(Animator anim) | 和前面动画一起执行 |
public Builder before(Animator anim) | 执行前面的动画后才执行该动画 |
public Builder after(Animator anim) | 执行先执行这个动画再执行前面动画 |
public Builder after(long delay) | 延迟n毫秒之后执行动画 |
play(Animator anim)表示当前在播放哪个动画,另外的with(Animator anim)、before(Animator anim)、after(Animator anim)都是以play中的当前所播放的动画为基准的。
当play(playAnim)与before(beforeAnim)共用,则表示在播放beforeAnim之前,先播放playAnim动画;同样,当play(playAnim)与after(afterAnim)共用时,则表示在在播放afterAnim动画之后,再播放playAnim动画。
- 使用示例
/**
* 按照自定义顺序播放动画
* 首先ivImage09的颜色变化、位移和ivImage09,同时发生
* 等待前面的动画播放完后 ivImage11,ivImage12才开始动画
*
*/
ObjectAnimator objectAnimator01=ObjectAnimator.ofArgb(ivImage09, "BackgroundColor",
getResources().getColor(R.color.colorPrimary),
getResources().getColor(R.color.colorAccent),
getResources().getColor(R.color.colorPrimary));
ObjectAnimator objectAnimator02 = ObjectAnimator.ofFloat(ivImage09, "TranslationY", 0, 300, 0);
ObjectAnimator objectAnimator03 = ObjectAnimator.ofFloat(ivImage10, "TranslationY", 0, 400, 0);
ObjectAnimator objectAnimator04 = ObjectAnimator.ofFloat(ivImage11, "TranslationY", 0, 500, 0);
ObjectAnimator objectAnimator05 = ObjectAnimator.ofFloat(ivImage12, "TranslationY", 0, 600, 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(objectAnimator01).with(objectAnimator02).with(objectAnimator03).before(objectAnimator04).before(objectAnimator05);
animatorSet.setDuration(2000);
animatorSet.start();
8-3 PropertyValuesHolder
- 多属性动画同时工作管理类。有时候我们需要同时修改多个属性,那就可以用到此类,具体如下:
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
九、ViewPropertyAnimator
9-1Google官方在Android 3.1系统中补充了ViewPropertyAnimator类,这个类便是专门为View动画而设计的。当然这个类不仅仅是为提供View而简单设计的,它存在以下特点:
1、专门针对View对象动画而操作的类。
2、提供了更简洁的链式调用设置多个属性动画,这些动画可以同时进行的。
3、拥有更好的性能,多个属性动画是一次同时变化,只执行一次UI刷新(也就是只调用一次invalidate,而n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)。
4、每个属性提供两种类型方法设置scaleX()/scaleXBy()。
5、该类只能通过View的animate()获取其实例对象的引用
9-2 每个属性,两种类型方法设置:
rotationX(20) 改变到某个值。 旋转到20度。再调用一次的话,由于已经到20度的位置,便不在有变化。
rotationXBy(20) 改变某个值的量。 旋转20度。再调用一次的话,继续旋转20度,到40度的位置。
9-3常见设置
view.animate()//获取ViewPropertyAnimator对象
//动画持续时间
.setDuration(5000)
//透明度
.alpha(0)
.alphaBy(0)
//旋转
.rotation(360)
.rotationBy(360)
.rotationX(360)
.rotationXBy(360)
.rotationY(360)
.rotationYBy(360)
//缩放
.scaleX(1)
.scaleXBy(1)
.scaleY(1)
.scaleYBy(1)
//平移
.translationX(100)
.translationXBy(100)
.translationY(100)
.translationYBy(100)
.translationZ(100)
.translationZBy(100)
//更改在屏幕上的坐标
.x(10)
.xBy(10)
.y(10)
.yBy(10)
.z(10)
.zBy(10)
//插值器
.setInterpolator(new BounceInterpolator())//回弹
.setInterpolator(new AccelerateDecelerateInterpolator())//加速再减速
.setInterpolator(new AccelerateInterpolator())//加速
.setInterpolator(new DecelerateInterpolator())//减速
.setInterpolator(new LinearInterpolator())//线性
//动画延迟
.setStartDelay(1000)
//是否开启硬件加速
.withLayer()
//监听
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Log.i("MainActivity", "run: onAnimationStart");
}
@Override
public void onAnimationEnd(Animator animation) {
Log.i("MainActivity", "run: onAnimationEnd");
}
@Override
public void onAnimationCancel(Animator animation) {
Log.i("MainActivity", "run: onAnimationCancel");
}
@Override
public void onAnimationRepeat(Animator animation) {
Log.i("MainActivity", "run: onAnimationRepeat");
}
})
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("MainActivity", "run: onAnimationUpdate==");
}
})
.withEndAction(new Runnable() {
@Override
public void run() {
Log.i("MainActivity", "run: end");
}
})
.withStartAction(new Runnable() {
@Override
public void run() {
Log.i("MainActivity", "run: start");
}
})
.start();
网友评论