Android补间动画和属性动画的区别及属性动画使用详解

补间动画和属性动画主要区别:

  • 作用对象不同,补间动画只能作用在view上,属性动画可以作用在所有对象上。

  • 属性变化不同,补间动画只是改变显示效果,不会改变view的属性,比如位置、宽高等,而属性动画实际改变对象的属性。

  • 动画效果不同,补间动画只能实现位移、缩放、旋转和透明度四种动画操作,而属性动画还能实现补间动画所有效果及其他更多动画效果。

新引入的属性动画机制已经不再是针对于 view 来设计的,也不限定于只能实现位移、缩放、旋转和透明度这几种动画操作,同时也不再只是一种视觉上的动画效果。它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性。我们只需要告诉系统动画的运行时长,需要执行哪种类型的动画,以及动画的初始值和结束值,剩下的工作就可以全部交给系统去完成了。

ValueAnimator

ValueAnimator是整个属性动画机制当中最核心的一个类,前面我们已经提到了,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个非常重要的类。

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
anim.setDuration(300);  
anim.start();

用法就是这么简单,现在如果你运行一下上面的代码,动画就会执行了。可是这只是一个将值从0过渡到1的动画,又看不到任何界面效果,我们怎样才能知道这个动画是不是已经真正运行了呢?这就需要借助监听器来实现了,如下所示:

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
anim.setDuration(300);  
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        float currentValue = (float) animation.getAnimatedValue();  
        Log.d("TAG""cuurent value is " + currentValue);  
    }  
});  
anim.start();

ObjectAnimator

相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡,但我们实际使用到这种功能的场景好像并不多。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。

不过虽说ObjectAnimator会更加常用一些,但是它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个类。那么既然是继承关系,说明ValueAnimator中可以使用的方法在ObjectAnimator中也是可以正常使用的,它们的用法也非常类似,这里如果我们想要将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,就可以这样写:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();

可以看到,我们还是调用了ofFloat()方法来去创建一个ObjectAnimator的实例,只不过ofFloat()方法当中接收的参数有点变化了。这里第一个参数要求传入一个object对象,我们想要对哪个对象进行动画操作就传入什么,这里我传入了一个textview。第二个参数是想要对该对象的哪个属性进行动画操作,由于我们想要改变TextView的不透明度,因此这里传入"alpha"。后面的参数就是不固定长度了,想要完成什么样的动画就传入什么值,这里传入的值就表示将TextView从常规变换成全透明,再从全透明变换成常规。之后调用setDuration()方法来设置动画的时长,然后调用start()方法启动动画。

到目前为止,ObjectAnimator的用法还算是相当简单吧,但是我相信肯定会有不少朋友现在心里都有同样一个疑问,就是ofFloat()方法的第二个参数到底可以传哪些值呢?

  • translationX、translationY:这两个属性作为一种增量来控制着View对象从它布局容器的左上角坐标开始的位置。

  • rotation、rotationX、rotationY:这三个属性控制着View对象围绕它的支点进行2D和3D的旋转。

  • scaleX和scaleY:这两个属性控制着View对象围绕它的支点进行2D缩放。

  • pivotX和pivotY:这两个属性控制着View对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认情况下,该支点的位置就是View对象的中心点。

  • alpha:它表示View对象的alpha透明度。

  • x、y:这是两个简单的实用的属性,它描述了View对象在它的容器中最终的位置。

以上只是view中常用的动画操作,为什么会是这些勒?

其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法。

比如第二个参数为alpha,那么该对象一定有setAlpha和getAlpha方法,而且 set方法参数为float类型,get方法返回值为float类型。使用Android Studio 开发时如果该值错误,不符合以上条件,会自动检测提醒错误。

至于后面的参数含义可以查找对应的set方法来理解。比如ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f) 就是循环调用该对象的setAlpha方法。

动画实践

1、平移动画代码如下:

ObjectAnimator.ofFloat(view, "translationX", 0f, 200f)
.setDuration(500)
.start();

2、透明度动画代码如下:

ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
.setDuration(1500)
.start();

3、旋转动画代码如下:

ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f)
.setDuration(1000)
.start();

4、位移动画代码如下:

ObjectAnimator.ofFloat(view, "translationX"0, view.getWidth())
.setDuration(1000)
.start();

5、背景颜色渐变代码如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    // API 必须代码 23 才能使用ofArgb
    ObjectAnimator animator = ObjectAnimator.ofArgb(view, "backgroundColor"0xffff00ff0xffffff000xffff00ff);
    animator.setDuration(4000);
    animator.start();
}

6、组合动画-----伸缩、透明度动画同时开始代码如下:

AnimatorSet animatorSet = new AnimatorSet();//组合动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
 
animatorSet.setDuration(2000);
animatorSet.setInterpolator(new DecelerateInterpolator());
animatorSet.play(scaleX).with(scaleY).with(alpha);//动画同时开始
animatorSet.start();

7、组合动画-----缩放、透明度动画先后开始代码如下:

AnimatorSet animatorSet = new AnimatorSet();//组合动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 2f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 2f);
ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
ObjectAnimator scaleX2 = ObjectAnimator.ofFloat(view, "scaleX", 2f, 0f);
ObjectAnimator scaleY2 = ObjectAnimator.ofFloat(view, "scaleY", 2f, 0f);
 
animatorSet.setDuration(2000);
animatorSet.setInterpolator(new DecelerateInterpolator());
animatorSet.play(scaleX).with(scaleY).before(alpha).before(scaleX2).before(scaleY2);//alpha 动画后执行
animatorSet.start();

  • after(Animator anim) :将现有动画插入到传入的动画之后执行

  • after(long delay) :将现有动画延迟指定毫秒后执行

  • before(Animator anim): 将现有动画插入到传入的动画之前执行

  • with(Animator anim) :将现有动画和传入的动画同时执行

在动画执行前,还可以为动画添加监听事件

animatorSet.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
        //动画开始的时候调用
    }
 
    @Override
    public void onAnimationEnd(Animator animation) {
        //画结束的时候调用
    }
 
    @Override
    public void onAnimationCancel(Animator animation) {
        //动画被取消的时候调用
    }
 
    @Override
    public void onAnimationRepeat(Animator animation) {
        //动画重复执行的时候调用
    }
});

有时候,我们只想监听其中的某个事件,其他的我们并不关心。官方还是很人性化得为我们提供了另一个类:AnimatorListenerAdapter,在这个类中,只要重写我们想要的监听事件就可以了。

animatorSet.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationStart(Animator animation) {
 
    }
});

8、按钮控件宽度增加动画代码如下:

ObjectAnimator animator = ObjectAnimator.ofInt(v, "width", v.getWidth(), v.getWidth() * 2);
animator.setDuration(1000);
animator.start();

9、抛物线动画代码如下:

ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(1500);
valueAnimator.setObjectValues(new PointF(0100));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
 
    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        /**x方向200px/s ,则y方向0.5 * 200 * t**/
        PointF point = new PointF();
        point.x = 200 * fraction * 3;
        point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
        return point;
    }
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        PointF point = (PointF) animation.getAnimatedValue();
        v.setX(point.x);
        v.setY(point.y);
    }
});

posted @ 2019-04-10 17:48  小马☼猿  阅读(4510)  评论(0编辑  收藏  举报