动画详解

前言:

看了很多关于android动画的博客,现在自己做一个简单总结吧.

动画分类

补间动画(Tween)

两个关键帧做补间动画已达到所需效果.


AlphaAnimation:透明度(alpha)渐变效果,对应<alpha/>标签。

TranslateAnimation:位移渐变,需要指定移动点的开始和结束坐标,对应<translate/>标签。

ScaleAnimation:缩放渐变,可以指定缩放的参考点,对应<scale/>标签。

RotateAnimation:旋转渐变,可以指定旋转的参考点,对应<rotate/>标签。

AnimationSet:组合渐变,支持组合多种渐变效果,对应<set/>标签。

几种动画的xml--Demo:

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromAlpha="1.0"
    android:toAlpha="0.1"
    android:duration="2000"/>
 <!-- 
 fromAlpha :起始透明度
 toAlpha:结束透明度
 1.0表示完全不透明
 0.0表示完全透明
  -->
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:duration="1000"
    android:repeatCount="1"
    android:repeatMode="reverse"/>
<!-- 
fromDegrees:表示旋转的起始角度
toDegrees:表示旋转的结束角度
repeatCount:旋转的次数  默认值是0 代表旋转1次  如果值是repeatCount=4 旋转5次,值为-1或者infinite时,表示补间动画永不停止
repeatMode 设置重复的模式。默认是restart。当repeatCount的值大于0或者为infinite时才有效。
repeatCount=-1 或者infinite 循环了
还可以设成reverse,表示偶数次显示动画时会做与动画文件定义的方向相反的方向动行。
 -->


<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromXScale="0.2"
    android:toXScale="1.5"
    android:fromYScale="0.2"
    android:toYScale="1.5"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="2000"/>

<!-- 
fromXScale:表示沿着x轴缩放的起始比例
toXScale:表示沿着x轴缩放的结束比例

fromYScale:表示沿着y轴缩放的起始比例
toYScale:表示沿着y轴缩放的结束比例

图片中心点:
  android:pivotX="50%" 
    android:pivotY="50%"

 -->

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:fromXDelta="0"
    android:toXDelta="320"
    android:fromYDelta="0"
    android:toYDelta="0"
    android:duration="2000"/> 
    
<!-- 
  android:interpolator 动画的渲染器
  1、accelerate_interpolator(动画加速器) 使动画在开始的时候 最慢,然后逐渐加速
  2、decelerate_interpolator(动画减速器)使动画在开始的时候 最快,然后逐渐减速
  3、accelerate_decelerate_interpolator(动画加速减速器)
           中间位置分层:  使动画在开始的时候 最慢,然后逐渐加速         
          使动画在开始的时候 最快,然后逐渐减速  结束的位置最慢
 fromXDelta  动画起始位置的横坐标
 toXDelta    动画起结束位置的横坐标
 fromYDelta  动画起始位置的纵坐标
 toYDelta   动画结束位置的纵坐标
 duration 动画的持续时间
 -->

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:shareInterpolator="true" >

    <scale
        android:duration="2000"
        android:fromXScale="0.2"
        android:fromYScale="0.2"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.5"
        android:toYScale="1.5" />

    <rotate
        android:duration="1000"
        android:fromDegrees="0"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:toDegrees="360" />

    <translate
        android:duration="2000"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="320"
        android:toYDelta="0" />

    <alpha
        android:duration="2000"
        android:fromAlpha="1.0"
        android:toAlpha="0.1" />

    

</set>


代码中如何调用xml的动画?
 Animation animation = AnimationUtils.loadAnimation(this,  
                R.anim.translate_demo);  
  
 animation.setRepeatCount(Animation.INFINITE);//循环显示  
 imageView.startAnimation(animation);  

帧动画

很多张图片,快速翻动已达到动画效果,类似以前的电影.

属性动画

属性动画是3.0以后才有的,所以要支持低版本需要nineoldandroids的jar包才可以.

了解属性动画前有两个概念非常重要:
TimeInterpolator(时间差值器)TypeEvaluator(类型估值算法)

TimeInterpolator

它的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器:动画两头慢中间快)
和DecelerateInterpolator(减速插值器:动画越来越慢)等;
比如线性运动100m,需要10s,那么在5s的时候,这个线性插值器返回的实际上是0.5

TypeEvaluator

它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator(针对整型属性)、FloatEvaluator(针对浮点型属性)和ArgbEvaluator(针对Color属性)。
比如线性运动100m,需要10s,那么在50m的时候(也就是属性改变50%的时候),这个估值器返回的实际上是50


属性动画

要求:动画作用的对象提供该属性的get和set方法,属性动画根据你传递的该属性的初始值和最终值,以动画的效果多次去调用set方法,
每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。
比如对object的属性xxx做动画,如果想让动画生效,要同时满足两个条件:
1.object必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值(如果这条不满足,程序直接Crash)

2.object的setXxx对属性xxx所做的改变必须能够通过某种方法反映出来,比如会带来ui的改变啥的(如果这条不满足,动画无效果但不会Crash)


就比如第二点,有个小例子:

比如想改变button的宽度从100到500,那么直接写是达不到效果的!

    private void performAnimate() {
        ObjectAnimator.ofInt(mButton, "width", 500).setDuration(5000).start();
    }

    @Override
    public void onClick(View v) {
        if (v == mButton) {
            performAnimate();
        }
    }


什么呢?
button的setWidth是继承TextView的,而TextView的setWidth并没有改变其真正的宽度!他设置的是android:width属性,而非android:layout_width的属性.
所以看不到动画效果的.
如何解决呢?
1. 给你的对象加上get和set方法,如果你有权限的话(很多时候往往没有,比如这里举得例子)
2. 用一个类来包装原始对象,间接为其提供get和set方法
3. 采用
ValueAnimator,监听动画过程,自己实现属性的改变

第二种方法实现(推荐,简单好用):
</pre><pre name="code" class="java">    private void performAnimate() {
        ViewWrapper wrapper = new ViewWrapper(mButton);
        ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(5000).start();
    }

    @Override
    public void onClick(View v) {
        if (v == mButton) {
            performAnimate();
        }
    }

    private static class ViewWrapper {
        private View mTarget;

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

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

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

第三种方法实现:

ValueAnimator本身不作用于任何对象,它可以对一个值做动画,然后我们可以监听其动画过程,在动画过程中修改我们的对象的属性值,这样也就相当于我们的对象做了动画。
    private void performAnimate(final View target, final int start, final int end) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);//值从1变到100

        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

            //持有一个IntEvaluator对象,方便下面估值的时候使用
            private IntEvaluator mEvaluator = new IntEvaluator();

            @Override
            public void onAnimationUpdate(ValueAnimator animator) {
                //获得当前动画的进度值,整型,1-100之间
                int currentValue = (Integer)animator.getAnimatedValue();
                Log.d(TAG, "current value: " + currentValue);

                //计算当前进度占整个动画过程的比例,浮点型,0-1之间
                float fraction = currentValue / 100f;

                //这里我偷懒了,不过有现成的干吗不用呢
                //直接调用整型估值器通过比例计算出宽度,然后再设给Button
                target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
                target.requestLayout();
            }
        });

        valueAnimator.setDuration(5000).start();//值从1变到100所需要5000ms
    }

    @Override
    public void onClick(View v) {
        if (v == mButton) {
            performAnimate(mButton, mButton.getWidth(), 500);
        }
    }

关于这个ValueAnimator我要再说一下,拿上例来说,它会在5000ms内将一个数从1变到100,然后动画的每一帧会回调onAnimationUpdate方法,在这个方法里,我们可以获取当前的值(1-100),根据当前值所占的比例(当前值/100),我们可以计算出Button现在的宽度应该是多少,比如时间过了一半,当前值是50,比例为0.5,假设Button的起始宽度是100px,最终宽度是500px,那么Button增加的宽度也应该占总增加宽度的一半,总增加宽度是500-100=400,所以这个时候Button应该增加宽度400*0.5=200,那么当前Button的宽度应该为初始宽度+ 增加宽度(100+200=300)。上述计算过程很简单,其实它就是整型估值器IntEvaluator的内部实现,所有我们不用自己写了,直接用吧。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值