Android 动画机制与使用技巧

本文详细介绍了Android中的视图动画和属性动画。视图动画包括AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation,适用于简单动画效果,但不支持交互。属性动画则在Android 3.0后引入,可以改变对象属性并响应事件,提供更丰富的动画效果。ObjectAnimator是其核心,通过get、set方法控制属性值。文中还探讨了如何处理无get、set方法的属性,以及如何使用AnimatorSet和ValueAnimator实现复杂的动画组合和控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       Animation框架定义了透明度、旋转、缩放和位移几种常见的动画,而且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApply.getMatrix()),通过矩阵运算完成动画帧。如果动画没有完成,就继续调用invalidate()函数,启动下次绘制来驱动动画,从而完成整个动画的绘制。

        视图动画使用简单,效果丰富,它提供了AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation四种动画方式,并提供了AnimationSet动画集合,混合使用多种动画。在Android3.0之前,视图动画一家独大,但随着Android3.0之后属性动画框架的推出,它的风光就大不如前了。相比属性动画,视图动画的一个非常大的缺陷就是不具备交互性,当某个元素发生视图动画后,其响应事件的位置还依然在动画前的地方,所以视图动画只能做普通的动画效果,避免交互的发生。但是它的优点也非常明显,即效率比较高切使用方便。

       视图动画使用非常简单,不仅可以通过XML文件来描述一个动画过程,同样也可以使用代码来控制整个动画过程。

       例:

     1.透明度动画

 

AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(1000);
textView.startAnimation(alphaAnimation);

    2.旋转动画

 

RotateAnimation rotateAnimation = new RotateAnimation(0,360,100,100);
rotateAnimation.setDuration(1000);
textView.setAnimation(rotateAnimation);

       其参数分别为旋转的起始角度和旋转中心点的坐标,当然,可以通过设置参数来控制旋转动画的参考系,代码如下(这里设置旋转参考系为自身中心点)。

RotateAnimation rotateAnimation = new RotateAnimation(0,360,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(1000);
textView.setAnimation(rotateAnimation);

   3.位移动画

      为视图移动时增加位移动画

 

TranslateAnimation rotateAnimation = new TranslateAnimation(0,200,0,300);
rotateAnimation.setDuration(1000);
textView.setAnimation(rotateAnimation);

   4.缩放动画

     为视图的缩放增加动画效果

 

ScaleAnimation scaleAnimation = new ScaleAnimation(0,2,0,2);
scaleAnimation.setDuration(1000);
textView.setAnimation(scaleAnimation);

  与旋转动画一样,缩放动画也可以设置缩放的中心点,代码如下(这里的参数效果与前面设置的选择中心为自身中心效果相同)

 

ScaleAnimation scaleAnimation = new ScaleAnimation(0,2,0,2, Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(1000);
textView.setAnimation(scaleAnimation);

动画集合

     通过AnimationSet,可以将动画以组合的形式展现出来:

 

AnimationSet animationSet = new AnimationSet(true);
animationSet.setDuration(1000);


AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
alphaAnimation.setDuration(1000);
animationSet.addAnimation(alphaAnimation);

ScaleAnimation scaleAnimation = new ScaleAnimation(0,2,0,2, Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(1000);
animationSet.addAnimation(scaleAnimation);


textView.setAnimation(animationSet);

    对于动画事件,Android也提供了对应的监听回调,要添加相应的监听方法

 

animationSet.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
        
    }

    @Override
    public void onAnimationEnd(Animation animation) {

    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
});

通过这个监听回调,可以获取到动画的开始、结束和重复事件,并针对相应的事件做出不同的处理。

       通过前面的实例,可以发现视图动画的效果比较局限,而在这样一个对UI、交互需求越来越高的年代,视图动画注定会被更丰富的效果所取代。

    Android属性动画

       由于Android3.0之前已有的动画框架Animation存在一些局限性---------动画改变的只是显示,并不能响应事件。因此,在Android3.0之后,Google就提出了属性动画这样一个新的动画框架,帮助开发者实现更加丰富的动画效果。

     而在Animator框架中使用最多的就是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator进行更精细化的控制,只控制一个对象的一个属性,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画。而且ObjeactAnimator能够自动驱动,可以调用setFrameDelay(logframeDelay)设置动画帧之间的间隙时间,调整帧率,减少动画过程中频繁绘制界面,而在不影响动画效果的前提 下减少CPU资源消耗。最重要的是,属性动画通过调用属性的get、set方法来真实地控制了一个View的属性值,因此强大的属性动画框架,基本可以实现所有的动画效果。

      下面我们来看看属性动画中最基础的ObjectAnimator.

    ObjectAnimator

   ObjectAnimator是属性动画框架中最重要的实行类,创建一个ObjectAnimator只需要通过他的静态工厂类直接返回一个ObjectAnimator对象。参数包括一个对象和对象的属性名称,但这个属性必须要有get和set函数,内部会通过java反射机制来调用set函数修改对象属性值。同样,你也可以调用setInterpolator设置相应的差值器。

 

ObjectAnimator objectAnimator     = ObjectAnimator.ofFloat(textView,"translationX",300);
objectAnimator.setDuration(1000);
objectAnimator.start();

    通过ObjectAnimator的静态工厂方法,创建一个ObjectAnimator对象。第一个参数自然是需要操纵的View,第二个参数则是要操纵的属性,而最后一个参数是一个可变数组参数,需要传递进去该属性变化的一个取值过程,这里只设置了一个参数,即变化到300。当然,与视图动画一样,也可以给属性动画设置显示时长、差值器等属性,这些参数与在视图动画中的设置方法类似。

   不过使用ObjectAnimator的时候,有一点非常重要,那就是要操纵的属性必须具有get、set方法,不然ObjectAnimator就无法起效。下面是一些常用的可以直接使用属性动画的属性值。

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

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

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

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

5.x和y:这是两个简单实用的属性,它描述了View对象在它的容器中的最终位置,它是最初的左上角坐标和translationX,translationY值得累计和。

6.alpha:它表示View对象的alpha透明度。默认值是1(不透明),0代表完全透明(不可见)。

  由以上可知,视图动画所实现的动画效果,在这里基本都已经包含了。

 那么对于一个属性没有get、set方。Google在应用层提供了两种方案来解决这个问题,一个是通过自定义一个属性类或者包装类,来间接地给这个属性增加get、set方法;或者通过ValueAnimator来实现。

 

   private static class WrapperView {

        private View mTarget;

        public WrapperView(View target) {
            mTarget = target;
        }

        public int getWidth() {
            return mTarget.getLayoutParams().width;
        }

        public void setWidth(int width) {
            mTarget.getLayoutParams().width = width;
            mTarget.requestLayout();
        }
    }
}

   通过以上代码,就给一个属性包装了一层,并给它提供了get、set方法。使用时只需要操纵包装类就可以间接调用到get、set方法了。

 

WrapperView wrapperView     = new WrapperView(textView);
ObjectAnimator.ofInt(wrapperView,"width",500).setDuration(5000).start();

    PropertyValuesHolder

     类似视图动画中的AnimatorSet,在属性动画中,如果针对同一个对象的多个属性,要同时作用多种动画,可以使用PropertyValueHolder来实现。比如举例的平移动画,如果需要平移的过程中,同时改变X,Y轴的缩放,可以这样实现。

      

PropertyValuesHolder pp1 = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder pp2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder pp3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);

ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(textView, pp1, pp2, pp3);
objectAnimator.setDuration(1000).start();

     在代码中,分别使用propertyValuesHolder对象来控制translationX、scaleX、scaleY这三个属性,最后调用ObjectAnimator.ofpropertyValuesHolder方法实现多属性动画的共同作用,整个实现方法非常类似AnimationSet的使用。

        ValueAnimator

    ValueAnimator在属性动画中占有非常重要的地位,虽然不像ObjectAnimator那样耀眼,但他却是属性动画的核心所在,ObjectAnimator也是继承自ValueAnimator

      ValueAnimator本身不提供任何动画效果,它更像一个数值发生器,用来产生具有一定规律的数字,从而让调用者来控制动画的实现过程,ValueAnimator的一般使用方法如下所示,通常情况下,在ValueAnimator的AnimatorUpdateListener中监听数值的变换,从而完成动画的变换。

    

ValueAnimator valueAnimator      = ValueAnimator.ofFloat(1,100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float value  = (Float) animation.getAnimatedValue();
        Log.e("fsdfsfsfsdfdsfdsf",value+"");
    }
});
valueAnimator.start();

     动画事件的监听

一个完整的动画具有Start、Repeat、End、Cancel四个过程,通过Android提供的接口,可以很方便地监听到这四个事件。

 

ObjectAnimator objectAnimator= ObjectAnimator.ofFloat(textView,"alpha",0.5f);
objectAnimator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationCancel(Animator animation) {
        super.onAnimationCancel(animation);
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
        super.onAnimationRepeat(animation);
    }

    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
    }
});

      AnimatorSet

      对于一个对象作用多个属性动画的效果,前面已经用PropertyValuesHolder实现了这样的效果。而AnimatorSet不仅能实现这样的效果,同时也能实现更为精确地顺序控制。同样是实现上面使用PropertyValuesHolder演示的那个动画效果,如果使用AnimatorSet来实现:

ObjectAnimator animator1 = ObjectAnimator.ofFloat(textView, "translationX", 300f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(textView, "scaleX", 1f, 0f, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(textView, "scaleY", 1f, 0f, 1f);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(1000);
animatorSet.playTogether(animator1,animator2,animator3);
animatorSet.start();

      在属性动画中,AnimatorSet正是通过playTogether()、playSequentially()、animSet.play.with()、defore()、after()这些方法来控制多个动画的协同工作方式,从而做到对动画播放顺序的精确控制。

     在XML中使用属性动画

  属性动画同视图动画一样,也可以直接写在XML文件中。

 

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType"
    >
</objectAnimator>

    可以发现,属性动画与视图动画在XML文件中的写法很相似。

    在程序中使用XML定义的属性动画也非常简单

 

 Animator animator = AnimatorInflater.loadAnimator(this,R.animator.scale);
animator.setTarget(textView);
animator.start();

    View的animate方法

      在Android3.0之后,Google给View增加了animate方法来直接驱动属性动画。其实animate方法可以认为是属性动画的一种简写方式。

textView.animate()
        .alpha(0)
        .y(300)
        .setDuration(300)
        .withStartAction(new Runnable() {
            @Override
            public void run() {
                
            }
        })
        .withEndAction(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        
                    }
                });
                
            }
        }).start();

     Android布局动画

   所谓布局动画是指作用在ViewGroup上,给ViewGroup增加View时添加一个动画过渡效果。

   最简单的布局动画是在ViewGroup的XML中,使用以下代码来打开布局动画。

 

android:animateLayoutChanges="true"

    通过以上代码设置,当ViewGroup添加View时,子View会呈现逐渐显示的过渡效果,不过这个效果是Android默认的显示的过渡效果,且无法使用自定义的动画来替换这个效果。

    另外,还可以通过LayoutAnimatonController类来自定义一个子View的过渡效果

 

//设置过渡动画
ScaleAnimation sa = new ScaleAnimation(0,1,0,1);
sa.setDuration(2000);
//设置布局动画的显示属性
LayoutAnimationController layoutAnimationController      =new LayoutAnimationController(sa,0.5f);\
layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
//为ViewGroup设置布局动画
linearLayout.setLayoutAnimation(layoutAnimationController);

     通过以上代码,给LinearLayout增加了一个视图动画,让子View在出现的时候,有一个缩放的动画效果。

    LayoutAnimatonController的第一个参数,是需要作用的动画,而第二个参数,则是每个子View显示的delay时间。当delay时间不为0时,可以设置子View显示的顺序,如下所示。

LayoutAnimationController.ORDER_NORMAL----顺序
LayoutAnimationController.ORDER_RANDOM  ---随机
LayoutAnimationController.ORDER_REVERSE   ------反序

   InterPolators(差值器)

    差值器是动画中一个非常重要的概念,通过差值器,可以定义动画变换速率,这一点非常类似物理中的加速度,其作用主要是控制目标变量的变化值进行对应的变化。同样的一个动画变换起始值,在不同的差值器的作用下,每个单位时间内所达到的变化值也是不一样的。  

    

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值