Android开发艺术探索__android动画深入分析(七)

分类

Android的动画可以分为三种:
1.View动画,也叫补间动画(Tween Animation)
2.帧动画,也叫逐帧动画(Frame Animation)
3.属性动画

View动画

View动画的作用对象是View,分为四种:

静态创建:

创建文件夹>>右键整个module,创建resource direct,选择xml格式,名为anim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
     android:shareInterpolator="true"
     android:duration="3000"
     android:fillAfter="true"
>
    //子类也有duration
    <alpha android:fromAlpha="0"
           android:toAlpha="0.8"/>
    <scale android:fromXScale="0"
           android:fromYScale="0"
           android:pivotX="50"
           android:pivotY="50"
           android:toXScale="1"
           android:toYScale="1"/>
    <rotate android:fromDegrees="0"
            android:pivotX="50"
            android:pivotY="50"
            android:toDegrees="360"/>
    <translate android:fromXDelta="0"
               android:fromYDelta="0"
               android:toXDelta="100"
               android:toYDelta="100"/>
</set>
android:interpolator:
插值器,默认为#android:anim/accelerate_decelerate_interpolar

android:shareInterpolator:
是否共享插值器

andorid:fillAtler:
动画结束后画面是否停留在最后一刻的位置

andorid:fillAtler:fillBefore:
动画结束后是否停留在动画的第一帧
在代码中开始动画:
    public void test(View view) {
    //使用AnimationUtils.loadAnimation(context,R.anim.xxx)来将静态动画加载进入代码
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation);
        btn.startAnimation(animation);
    }

动态创建动画

        //单个动画
        ScaleAnimation scaleAnimation = new ScaleAnimation(0f,1f,0f,1f
        ,btn.getWidth()/2,btn.getHeight()/2);
        scaleAnimation.setDuration(1000);
        btn.startAnimation(scaleAnimation);
        //动画组合
        AnimationSet animationSet = new AnimationSet(false);
        animationSet.addAnimation(scaleAnimation);
        animationSet.setDuration(1000);
        btn.startAnimation(animationSet);

设置补间动画的监听器

    //设置监听器
    private void addAnimationListener(Animation animation) {

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

            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

自定义补间动画

自定义补间动画说难不难,说简单不简单,因为这主要是数学的应用;
继承Animation这个类,
实现initialize(),在里面做一些初始化操作
实现applyTransformation(),在里面进行矩阵的变换,可以利用Camera来简化矩阵变化你的过程
3D的旋转效果demo:

package com.example.android.apis.animation;

import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.graphics.Camera;
import android.graphics.Matrix;

/**
 * An animation that rotates the view on the Y axis between two specified angles.
 * This animation also adds a translation on the Z axis (depth) to improve the effect.
 */
public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;

    /**
     * Creates a new 3D rotation on the Y axis. The rotation is defined by its
     * start angle and its end angle. Both angles are in degrees. The rotation
     * is performed around a center point on the 2D space, definied by a pair
     * of X and Y coordinates, called centerX and centerY. When the animation
     * starts, a translation on the Z axis (depth) is performed. The length
     * of the translation can be specified, as well as whether the translation
     * should be reversed in time.
     *
     * @param fromDegrees the start angle of the 3D rotation
     * @param toDegrees the end angle of the 3D rotation
     * @param centerX the X center of the 3D rotation
     * @param centerY the Y center of the 3D rotation
     * @param reverse true if the translation should be reversed, false otherwise
     */
    public Rotate3dAnimation(float fromDegrees, float toDegrees,
            float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float fromDegrees = mFromDegrees;
        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

        final float centerX = mCenterX;
        final float centerY = mCenterY;
        final Camera camera = mCamera;

        final Matrix matrix = t.getMatrix();

        camera.save();
        if (mReverse) {
            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
        } else {
            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
        }
        camera.rotateY(degrees);
        camera.getMatrix(matrix);
        camera.restore();

        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}

帧动画

参考动漫,动态的画面是由多张静态的画面在单位时间内连续变换而产生的动画效果,本质上也是view动画的一种;

使用方法

在res/drawable中创建一个xml文件,以animation-list为根元素
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false"> //是否只使用一次,false则会不停的循环
    <item android:drawable="@drawable/frame_animation_1" android:duration="1000"/>
    <item android:drawable="@drawable/frame_animatiion_2" android:duration="1000"/>
    <item android:drawable="@drawable/frame_animation_1" android:duration="1000"/>
    <item android:drawable="@drawable/frame_animatiion_2" android:duration="1000"/>
</animation-list>
    public void test(View view) {
        btn.setBackgroundResource(R.drawable.frame_animation);
        AnimationDrawable animationDrawable = (AnimationDrawable) btn.getBackground();
        animationDrawable.start();
    }

View动画的使用场景:作为Viewgroup中子元素的出场动画

静态使用

在drawable中创建xml文件,
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/animation"//指定补间动画
    android:animationOrder="normal"//子元素动画的顺序 
    android:delay="10">
</layoutAnimation>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.junx.viewanimationobjectanimator.Animation.AnimationActivity"
    android:layoutAnimation="@anim/layout_animation"
    >
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.junx.viewanimationobjectanimator.Animation.AnimationActivity"
    //指定viewgroup的android:layoutAnimation属性
    android:layoutAnimation="@anim/layout_animation"
    >

动态使用

    public void layoutAnimation(ListView lv){
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation);

        LayoutAnimationController layoutAnimationController 
        = new LayoutAnimationController(animation);
        layoutAnimationController.setDelay(1f);
        layoutAnimationController.setOrder(layoutAnimationController.ORDER_RANDOM);
        lv.setLayoutAnimation(layoutAnimationController);
    }

View动画的使用场景:Activity的切换效果

    public void test(View view) {
        Intent intent = new Intent(this, FrameAnimationActivity.class);
        startActivity(intent);
        //第一个参数是被打开的页面的进来的动画,第二个参数是当前页面退出的动画效果
        //注意该方法必须在startActivity或者finish()后调用才能生肖
        overridePendingTransition(android.R.anim.fade_in,android.R.anim.slide_in_left);
    }
frament也可以是哟个setCustomAnimations()来设置切换效果

属性动画

View动画致命的缺点是,它只是看起来像一个动画而已,本质上view还是原来那样;

属性动画于api11被引入,我们可以通过开源动画库nineoldandroids来兼容以前的版本.nineoldandroids在aip11以前是通过代理view动画来实现,所以在api11以前它本质上还是view动画.
属性动画是通过操纵对象的属性来实现的,只要对象有这个属性,就能实现动画效果.默认间隔时间为300ms,帧率为10ms/帧;

ObjectAnimator

动态使用

    //单属性的动画
    private void singleAnimator() {
        ObjectAnimator backgroundColor = ObjectAnimator.ofInt(btn, "backgroundColor", 0xFFFF8080, 0xFF888888);
        backgroundColor.setDuration(3000);
        //argb的翻转效果,看起来过渡比较平缓
        backgroundColor.setEvaluator(new ArgbEvaluator());
        //设置重复次数为无限
        backgroundColor.setRepeatCount(ValueAnimator.INFINITE);
        //设置重复模式
        backgroundColor.setRepeatMode(ValueAnimator.REVERSE);
        backgroundColor.start();
    }

    //属性动画集合
    private void setAnimator() {
        AnimatorSet animatorSet = new AnimatorSet();
        //旋转效果
        animatorSet.playTogether
                //平移效果
                (ObjectAnimator.ofFloat(btn, "rotationX", 0, 360)
                , ObjectAnimator.ofFloat(btn, "rotationY", 0, 360)
                //缩放效果f
                , ObjectAnimator.ofFloat(btn, "scaleX", 1f, 1.5f)
                //透明度效果
                ,ObjectAnimator.ofFloat(btn, "scaleX", 1f, 1.5f,1f)
                ,ObjectAnimator.ofFloat(btn, "scaleY", 1f, 0.5f,1f)
                //平移效果
                ,ObjectAnimator.ofFloat(btn, "translationX", 1f,300f,0)
        );
        //支持链式调用
        animatorSet.setDuration(3000).start();
    }

静态使用

创建animator目录

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="1000"
        android:propertyName="translationX"
        android:repeatCount="0"
        android:repeatMode="restart"
        android:startOffset="15"
        android:valueFrom="1"
        android:valueTo="100"
        android:valueType="floatType" />
</set>
    //静态调用属性动画
    private void xml() {
        AnimatorSet animator = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.object_animator);
        animator.setTarget(btn);
        animator.start();
    }
<Set>对应AnimatorSet
    android:ordering:有两个可选值.together,动画集合中的子动画同时播放.sequentially,前后顺序播放.
<objectAnimator>对应ObjectAnimator
    android:propertyName,表示属性动画作用对象的属性的名称;
    android:duration,表示动画的时长
    android:valueFrom,表示属性的起始值
    android:valueTo
    android:startOffset,表示动画开始的延迟时间
    android:repeatCount,表示动画的重复次数.默认0,-1表示无限循环
    android:repeatMode,表示动画的重复模式
    android:valueType,表示属性值的单位或类型,如果是颜色则不需要处理,自动会颜色进行判断
<animator>对应ValueAnimator
    除了没有propertyName其余属性都和object相同.

属性动画的事件监听

    //属性动画的事件监听
    public void setAnimatorListener(Animator animator){
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {

            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
    }

ValueAnimator

是ObjectAnimator的父类,比objectanimator更为强大,但使用也更复杂;

ObjectAnimator生效的要求为:
1.object必须提供setXXX(),在没有传递初始值的时候必须额外提供getXXX().
2.对属性的改变必须能通过某种途径反应出来,比如使ui改变等等
例如,Button有getWidth(确实是获取view的宽度)和setWidth()(但setWidth不是改变view的宽度,就是这么奇葩)方法,但它是由View的子类TextView提供的用于改变tv的最大宽度和最小宽度,并不是我们理解上的视图上的宽度,所以objectanimator无效.

解决办法:
1.在有条件的情况下,加上getset方法
2.使用包装类包装需要改变的view(推荐)
3.使用ValueAnimator

静态使用

同objectanimator,在setitem中使用<animator>即可

动态使用

    //值动画
    private void valueAnimator() {
        ValueAnimator ofInt = ValueAnimator.ofInt(0,100);
        ofInt.setDuration(3000);
        ofInt.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            //估值器,或许用得上
            private IntEvaluator mEvaluator=new IntEvaluator();
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //获取当前值
                Integer animatedValue = (Integer) valueAnimator.getAnimatedValue();
                //获取动画进度 0-1f
                float animatedFraction = valueAnimator.getAnimatedFraction();
                //通过估值器来计算实时的数值第二三个参数为开始值和结束值
                Integer evaluate = mEvaluator.evaluate(animatedFraction, 0, 300);
                btn_value.getLayoutParams().width=evaluate;
                //更新btn的布局大小
                btn_value.requestLayout();
            }
        });
        ofInt.start();
    }

注意事项

1.注意OOM
2.注意内存泄漏,属性动画中无限循环的,需要在页面退出时及时处理.View动画则没有该问题
3.兼容性,在3.0以下,兼容性需要小心处理
4.View动画而能会导致setVisible()无效,可以调用view.clearAnimation()后setVisible()即可
5.不要使用px
6.3.0以下的平台,无论是属性动画还是view动画,都是不能点击的 .
7.请开启硬件加速
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值