动画特效大爆炸,玩转Android自定义动画(一)

本文深入浅出地讲解了Android视图动画的基本概念、基本用法、组合用法及自定义动画实现,包括Alpha、Scale、Rotate和Translate等动画类型,并提供了丰富的实例代码。

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

【题外话】先容我卖个萌装个B自我介绍一分钟哈,本猿自诩Android小白,天然呆谷粉米粉,爱开源,更爱漂亮妹纸(\(^o^)/~来跟我一起唱:原谅我一生放荡不羁爱自由~~~请自行脑补掌声三分钟^O^);好了好了说人话:本猿中南大学大三狗一个,每天最快乐的时光都与14寸的DeskTop为伴,曾经我是一个热爱并略懂Java和Android的小白,现在我是一个热爱并熟悉Java和Android的小白,就这样!聊技术谈梦想欢迎私信 @哈皮小猿_wondertwo


【1】 Android动画的基本概念

提起 Android 动画很多初学者就会一脸懵逼二阶茫然,想当初小猿我翻遍图书馆的一大堆入门书籍都找到有一个在讲 Android 动画机制,好在一颗痴迷技术的心让我自备燃料有始有终,最后总算弄明白了 Android 动画到底是个什么鬼。其实我们有木有经常用手机拍了很多漂亮照片以后,打开相册,点击更多,点击自动播放,这些静态的照片就会像幻灯片一样播放起来了有木有?这其实就是 Android 动画之一帧动画,把一组图片按顺序播放出来。是不是很简单呢? Android 动画分三类,下面我们简要的介绍一下:

  • 视图动画,即我们常说的 View 动画, View 动画有四种效果:透明度变化(AlphaAnimation),位移(TranslateAnimation),缩放(ScaleAnimation),旋转(RotateAnimation);
  • 帧动画,即 FrameAnimation ,可以简单的理解为放电影,又或者是手机相册的自动播放功能,把一组预先准备好的图片按顺序播放出来,就是一个帧动画;
  • 属性动画,即 PropertyAnimation ,我们知道动画都有很多属性,比如透明度的变化,比如位置的移动,比如旋转一定的角度,比如变化的速度、加速度等等这些,所谓属性动画就是通过设置透明度、位移、旋转角度、变化的加速度这些动画的属性,从而达到动画的效果;

视图动画 Added in API level 1 ,算是 Android 动画家族中的老腊肉了。那我们就从最基本的视图动画着手,由于篇幅的关系,帧动画和属性动画会放在下一篇文章中详细介绍,请大家继续关注哦。大家可能要吐槽说好的特效大爆炸呢?别急嘛!请往下看!下面就是狂炫酷帅的QQ客户端抖一抖动画和3D旋转&电视关闭画面的自定义动画哦!

QQ抖一抖

电视关闭画面&3D旋转


【2】 View动画的基本用法

哈哈,上面的自定义动画有木有惊艳到你呢?“每一个宅男心中都藏着一个女神”,我当然也不例外啦,你看的没错!画面中就是我的女神——张钧甯。告诉你上面的动画特效就是用自定义视图动画实现的哦,他们都是在四种最基本的视图动画的基础上稍加改进出来的,来我们看看四种基本的视图动画效果如何?

AlphaAnimation

ScaleAnimation

RotateAnimation

TranslateAnimation

分别对应着透明度变化(AlphaAnimation),缩放(ScaleAnimation),旋转(RotateAnimation),位移(TranslateAnimation),第五个是融合了前四种 View 动画的一个动画集合哦(AnimationSet);那到底是怎么实现的呢?定义动画既可以在代码中动态的定义,也可以在 xml 文件中定义。

先来看最简单的 View 动画。 View 动画的四种变换效果对应着 AlphaAnimation , ScaleAnimation , RotateAnimation , TranslateAnimation 这4个动画类,在 xml 文件中定义View动画,透明度动画对应的标签是 <alpha> ,缩放动画对应的标签是 <scale> ,旋转动画对应的标签是 <rotate> ,位移动画对应的标签是 <translate> 。下面我们来看代码,在 res 文件夹下新建文件夹 anim ,在 anim 目录新建 xml 文件 anim_view.xml ,根标签 <set> 就表示一个动画集合 AnimationSetshareInterpolator="true" 表示共享插值器,插值器会在后面详细解释;接着是4个View动画效果;代码如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="true" >

    <!--透明度-->
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />

    <!--缩放-->
    <scale
        android:fromXScale="0.5f"
        android:fromYScale="1.5f"
        android:toXScale="0.5f"
        android:toYScale="1.5f"
        android:pivotX="100"
        android:pivotY="100" />

    <!--位移-->
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="200"
        android:toYDelta="200" />

    <!--旋转-->
    <rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="200"
        android:pivotY="200" />

</set>

4个View动画效果标签中的属性值,分别对应着代码动态定义View动方法中接收的参数,这里做一下详细的解释:

  • alpha
    • fromAlpha —- 透明度起始值,0表示完全透明
    • toAlpha —- 透明度最终值,1表示不透明
  • scale
    • fromXScale —- 水平方向缩放的起始值,比如0
    • fromYScale —- 竖直方向缩放的起始值,比如0
    • toXScale —- 水平方向缩放的结束值,比如2
    • toYScale —- 竖直方向缩放的结束值,比如2
    • pivotX —- 缩放支点的x坐标
    • pivotY —- 缩放支点的y坐标(支点可以理解为缩放的中心点,缩放过程中这点的坐标是不变的;支点默认在中心位置)
  • translate
    • fromXDelta —- x起始值
    • toXDelta —- x结束值
    • fromYDelta —- y起始值
    • toYDelta —- y结束值
  • rotate
    • fromDegrees —- 旋转起始角度
    • toDegrees —- 旋转结束角度

除此之外,View动画还有一些常见的属性值,如下:

  • android:duration —- 动画的持续时间
  • android:fillAfter —- true表示保持动画结束时的状态,false表示不保持

上面就是通过 xml 文件定义的 View 动画,那怎么应用上面的动画呢?也很简单,通过 View 对象在代码中调用即可,值得注意的是,AnimationUtils.loadAnimation(this, R.anim.ani_view) 方法接收两个参数,第一个是当前的上下文环境,第二个就是我们通过 xml 定义的动画啦。代码如下:

ImageView ivAni = (ImageView) findViewById(R.id.iv_ani);
Animation ani = AnimationUtils.loadAnimation(this, R.anim.ani_view);
ivAni.startAnimation(ani);

上面介绍的是通过 xml 文件定义 View 动画,那怎样通过代码动态的定义 View 动画呢?也很简单,先上代码。

AlphaAni—-透明度动画代码如下,相信你经过前面的部分已经能很容易就看懂这些代码了,在 beginAnimation() 方法中,我们在3000ms的时间内把一个 LinearLayout 对象 llAlpha 的透明度从0到1,即从完全透明渐变到完全不透明,然后在 onCreate() 方法中调用 beginAnimation() 方法就能以透明度渐变动画的方式跳转到 AlphaAni :

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * AlphaAni----透明度动画
 * Created by wondertwo on 2016/3/11.
 */
public class AlphaAni extends Activity {

    private LinearLayout llAlpha;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alpha);
        llAlpha = (LinearLayout) findViewById(R.id.ll_alpha);
        beginAnimation();
    }

    // 启动动画
    private void beginAnimation() {
        AlphaAnimation alpha = new AlphaAnimation(0, 1);// 0---->1从透明到不透明
        alpha.setDuration(3000);// 设置动画持续时间
        llAlpha.startAnimation(alpha);// 启动动画
    }
}

ScaleAni—-缩放动画代码如下,与上面的透明度渐变动画类似,通过 ctrl+左键 查看源码可以知道,在创建 ScaleAnimation 缩放动画的对象的时候, ScaleAnimation(0, 2, 0, 2) 接受的四个参数分别是 ScaleAnimation(float fromX, float toX, float fromY, float toY)

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.ScaleAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * ScaleAni----缩放动画
 * Created by wondertwo on 2016/3/11.
 */
public class ScaleAni extends Activity {

    private LinearLayout llScale;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scale);
        llScale = (LinearLayout) findViewById(R.id.ll_scale);
        beginAnimation();
    }

    // 启动动画
    private void beginAnimation() {
        ScaleAnimation scale = new ScaleAnimation(0, 2, 0, 2);
        scale.setDuration(3000);
        llScale.startAnimation(scale);
    }
}

RotateAni—-旋转动画代码如下,表示把一个 View 对象从起始角度0旋转到360度,后面的四个参数 RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f 表示以中心位置为旋转支点:

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.RotateAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * RotateAni----旋转动画
 * Created by wondertwo on 2016/3/11.
 */
public class RotateAni extends Activity {

    private LinearLayout llRotate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rotate);
        llRotate = (LinearLayout) findViewById(R.id.ll_rotate);
        beginAnimation();
    }

    // 启动动画
    private void beginAnimation() {
        RotateAnimation rotate = new RotateAnimation(0, 360,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(3000);
        llRotate.startAnimation(rotate);
    }
}

TranslateAni—-位移动画代码如下,表示把 View 对象从起始坐标 (0, 0) 位移到 (200, 300) ,是不是很简单呢:

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * TranslateAni----位移动画
 * Created by wondertwo on 2016/3/11.
 */
public class TranslateAni extends Activity {

    private LinearLayout llTranslate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_translate);
        llTranslate = (LinearLayout) findViewById(R.id.ll_translate);
        beginAnimation();
    }

    // 启动动画
    private void beginAnimation() {
        TranslateAnimation translate = new TranslateAnimation(0, 200, 0, 300);
        translate.setDuration(3000);
        llTranslate.startAnimation(translate);
    }
}

【3】 View动画的高级用法

接下来我们趁热打铁,掌握 View 动画高级用法的好时机啦,所谓高级用法,其实也很简单,就是把上面的四种基本效果进行任意的排列组合,然后同时启动。为了更直观的感受,还是直接上动图吧请往下看,一种很酷炫的图片旋转飞入效果!

组合View动画

直接上代码如下,你看过肯定会觉得不能再简单啦,不就是把上面介绍的四种动画组合到一起了嘛,事实上就是这么简单。

package com.wondertwo.viewani;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;

import com.wondertwo.MainActivity;
import com.wondertwo.R;

/**
 * AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation四种视图动画的组合动画
 * Created by wondertwo on 2016/3/11.
 */
public class GroupAni extends Activity {

    private LinearLayout llGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_group);
        llGroup = (LinearLayout) findViewById(R.id.ll_group);
        beginAnimation();
    }

    // 启动组合动画
    private void beginAnimation() {
        // 创建动画集合
        AnimationSet aniSet = new AnimationSet(false);

        // 透明度动画
        AlphaAnimation alpha = new AlphaAnimation(0, 1);
        alpha.setDuration(4000);
        aniSet.addAnimation(alpha);

        // 旋转动画
        RotateAnimation rotate = new RotateAnimation(0, 360,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(4000);
        aniSet.addAnimation(rotate);

        // 缩放动画
        ScaleAnimation scale = new ScaleAnimation(1.5f, 0.5f, 1.5f, 0.5f);
        scale.setDuration(4000);
        aniSet.addAnimation(scale);

        // 位移动画
        TranslateAnimation translate = new TranslateAnimation(0, 160, 0, 240);
        translate.setDuration(4000);
        aniSet.addAnimation(translate);

        // 动画监听
        aniSet.setAnimationListener(new Animation.AnimationListener() {
            // 动画开始
            @Override
            public void onAnimationStart(Animation animation) {

            }

            // 动画结束,一般在这里实现页面跳转逻辑
            @Override
            public void onAnimationEnd(Animation animation) {
                // 动画结束后,跳转到主页面
                startActivity(new Intent(GroupAni.this, MainActivity.class));
            }

            // 动画重复
            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        // 把动画设置给llGroup
        llGroup.startAnimation(aniSet);
    }
}

唯一不同的是,我们这次是把四个 View 动画装进了一个动画集合(AnimationSet)中,至于动画集合,你就把他当做普通的 Set 集合使用就好,创建动画集合时传入的参数 false 表示动画集合中装入的和四个 View 动画不共享插值器。这肯定难不倒 Java 烂熟于心的你,对吧哈哈。到这里你已经学会 View 动画了,但是后面还有更高级用法呢!

特效动画_1

特效动画_2

还是一样先把代码贴出来,我们主要看动画的实现类代码,至于布局文件很简单这里就不讨论了。

package com.wondertwo.effect;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.BounceInterpolator;
import android.widget.ImageView;
import android.widget.Toast;

import com.wondertwo.R;

import java.util.ArrayList;


/**
 *
 * 常用动画的属性值有:
 *       - translationX、translationY----控制view对象相对其左上角坐标在X、Y轴上偏移的距离
 *       - rotation、rotationX、rotationY----控制view对象绕支点进行2D和3D旋转
 *       - scaleX、scaleY----控制view对象绕支点进行2D缩放
 *       - pivotX、pivotY----控制view对象的支点位置,这个位置一般就是view对象的中心点。围绕这个支点可以进行旋转和缩放处理
 *       - x、y----描述view对象在容器中的最终位置,是最初的左上角坐标和translationX、translationY值的累计和
 *       - alpha----表示view对象的透明度。默认值是1(完全透明)、0(不透明)
 *
 * Created by wondertwo on 2016/3/11.
 */
public class EffectAni extends AppCompatActivity implements View.OnClickListener {

    // ImageView组件id数组
    private int[] mRes = new int[]{R.id.iv_a, R.id.iv_b, R.id.iv_c, R.id.iv_d, R.id.iv_e};
    // ImageView对象集合
    private ArrayList<ImageView> mImViews = new ArrayList<>();
    private boolean flag = true;// 启动动画、关闭动画的标记位

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_effect);
        // for循环创建ImageView对象,并添加到集合中
        for (int i = 0; i < mRes.length; i++) {
            ImageView iv_a = (ImageView) findViewById(mRes[i]);
            iv_a.setOnClickListener(this);
            mImViews.add(iv_a);
        }
    }

    // 按钮点击事件
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_a:
                if (flag) {
                    startAnim();
                } else {
                    closeAnim();
                }
                break;
            default:
                Toast.makeText(EffectAni.this, "" + v.getId(), Toast.LENGTH_SHORT).show();
                break;
        }
    }

    // 关闭动画
    private void closeAnim() {
        // 创建ObjectAnimator对象,参数分别是动画要设置的View对象、动画属性、属性值
        ObjectAnimator animator0 = ObjectAnimator.ofFloat(mImViews.get(0),
                                                            "alpha",
                                                            0.5F,
                                                            1F);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImViews.get(1),
                                                            "translationY",
                                                            200F,
                                                            0);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImViews.get(2),
                                                            "translationX",
                                                            200F,
                                                            0);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImViews.get(3),
                                                            "translationY",
                                                            -200F,
                                                            0);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(mImViews.get(4),
                                                            "translationX",
                                                            -200F,
                                                            0);
        AnimatorSet aniSet = new AnimatorSet();
        aniSet.setDuration(4000);
        aniSet.setInterpolator(new BounceInterpolator());// 弹跳效果的插值器
        aniSet.playTogether(animator0,
                            animator1,
                            animator2,
                            animator3,
                            animator4);// 同时启动5个动画
        aniSet.start();

        // 重置标记位
        flag = true;
    }

    // 启动动画
    private void startAnim() {
        // 创建ObjectAnimator对象,参数分别是动画要设置的View对象、动画属性、属性值
        ObjectAnimator animator0 = ObjectAnimator.ofFloat(
                                                        mImViews.get(0),
                                                        "alpha",
                                                        1f,
                                                        0.5f);
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(
                                                        mImViews.get(1),
                                                        "translationY",
                                                        200f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(
                                                        mImViews.get(2),
                                                        "translationX",
                                                        200f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(
                                                        mImViews.get(3),
                                                        "translationY",
                                                        -200f);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(
                                                        mImViews.get(4),
                                                        "translationX",
                                                        -200f);
        AnimatorSet aniSet = new AnimatorSet();
        aniSet.setDuration(4000);
        aniSet.setInterpolator(new BounceInterpolator());// 弹跳效果的插值器
        aniSet.playTogether(animator0,
                            animator1,
                            animator2,
                            animator3,
                            animator4);// 同时启动5个动画
        aniSet.start();

        // 重置标记位
        flag = false;
    }
}

上面的代码逻辑很简单,在 ActivityonCreate() 方法中拿到五张一样的 ImageView 对象,其实你看到的元神分身效果就是这五张图片向不同方向做位移动画的结果啦,先用 int[] mRes 数组存放5个 ImageViewid ,然后在 ActivityonCreate() 方法中拿到五张一样的 ImageView 对象,在 closeAnim() 方法和 startAnim() 方法中分别对每张图片进行不同的 TranslateAnimation 处理。这里我们通过设置标记位 flag ,实现分身、归位两个效果的切换。


【4】 自定义View动画

当你看完上面的 View 动画,自定义 View 动画对你来说已经不在话下,我准备的两个 demo 你肯定很期待,分别是:模仿QQ客户端的抖一抖特效,和电视画面关闭&3D旋转,效果如下:

QQ抖一抖

上图就是模仿QQ客户端的抖一抖特效,可能由于Gif图片的录制的效果太差,显示的效果比我电脑上真实情况慢了好多,但是也基本能把这个效果显示出来了。先上代码!

package com.wondertwo.qqTremble;

import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * QQ抖一抖特效的自定义View动画实现
 * Created by wondertwo on 2016/3/17.
 */
public class QQTrembleAni extends Animation {
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        t.getMatrix().setTranslate(
                (float) Math.sin(interpolatedTime * 50) * 8,
                (float) Math.sin(interpolatedTime * 50) * 8
                );// 50越大频率越高,8越小振幅越小
        super.applyTransformation(interpolatedTime, t);
    }
}

上面这段代码就是我们自定义的QQ抖一抖动画了,所有的自定义动画都需要继承 android.view.animation.Animation 抽象类,然后重写 initialize()applyTransformation() 这两个方法,在 initialize() 方法中对一些变量进行初始化,在 applyTransformation() 方法中通过矩阵修改动画数值,从而控制动画的实现过程,这也是自定义动画的核心。 applyTransformation(float interpolatedTime, Transformation t) 方法在动画的执行过程中会不断地调用,可以看到接收的两个参数分别是 float interpolatedTime 表示当前动画进行的时间与动画总时间(一般在 setDuration() 方法中设置)的比值,从0逐渐增大到1; Transformation t 传递当前动画对象,一般可以通过代码 android.graphics.Matrix matrix = t.getMatrix() 获得 Matrix 矩阵对象,再设置 Matrix 对象,一般要用到 interpolatedTime 参数,以此达到控制动画实现的结果。可以看到在上面的代码中 t.getMatrix().setTranslate((float) Math.sin(interpolatedTime * 50) * 8, (float) Math.sin(interpolatedTime * 50) * 8) 设置了 Matrix 对象的 Translate ,传入的参数是一个正弦函数值,这个值是通过 interpolatedTime 参数计算出来的,这样就实现了动画在x,y轴两个方向上的来回抖动效果。

下面是QQ抖一抖动画的测试类 Activity ,代码如下:

package com.wondertwo.qqTremble;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;

import com.wondertwo.R;

/**
 * 模仿QQ抖一抖效果的测试类
 * Created by wondertwo on 2016/3/17.
 */
public class QQTrembleTest extends Activity {

    private RelativeLayout rlTremble;
    private Button btnTremble;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qq_tremble);
        rlTremble = (RelativeLayout) findViewById(R.id.rl_tremble);
        btnTremble = (Button) findViewById(R.id.btn_tremble);

        // 创建抖一抖动画对象
        final QQTrembleAni tremble = new QQTrembleAni();
        tremble.setDuration(800);// 持续时间800ms,持续时间越短频率越高
        tremble.setRepeatCount(2);// 重复次数,不包含第一次

        // 设置按钮点击监听
        btnTremble.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 启动抖一抖效果
                rlTremble.startAnimation(tremble);
            }
        });
    }
}

接着我们再看一个酷炫的自定义动画,类似电视机关机画面和图片3D旋转,效果如下!

电视关闭画面&3D旋转

直接上代码,电视关机画面效果动画 TVCloseAni 如下:

package com.wondertwo.custom;

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

/**
 * 通过矩阵变换模拟电视关闭效果,使图片的纵向比例不断缩小
 * Created by wondertwo on 2016/3/13.
 */
public class TVCloseAni extends Animation {

    private int mCenterWidth, mCenterHeight;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        // 设置默认时长
        setDuration(4000);
        // 保持动画的结束状态
        setFillAfter(true);
        // 设置默认插值器
        // setInterpolator(new BounceInterpolator());// 回弹效果的插值器
        mCenterWidth = width / 2;
        mCenterHeight = height /2;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        final Matrix matrix = t.getMatrix();
        matrix.preScale(1,
                        1 - interpolatedTime,
                        mCenterWidth,
                        mCenterHeight);
    }
}

图片3D旋转效果动画代码如下:

package com.wondertwo.custom;

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

/**
 *
 * Created by wondertwo on 2016/3/13.
 */
public class CustomAni extends Animation {

    private int mCenterWidth, mCenterHeight;
    private Camera mCamera = new Camera();
    private float mRotateY = 0.0f;

    // 一般在此方法初始化一些动画相关的变量和值
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        // 设置默认时长
        setDuration(4000);
        // 保持动画的结束状态
        setFillAfter(true);
        // 设置默认插值器
        setInterpolator(new BounceInterpolator());// 回弹效果的插值器
        mCenterWidth = width / 2;
        mCenterHeight = height /2;
    }

    // 暴露接口设置旋转角度
    public void setRotateY(float rotateY) {
        mRotateY = rotateY;
    }

    // 自定义动画的核心,在动画的执行过程中会不断回调此方法,并且每次回调interpolatedTime值都在不断变化(0----1)
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        final Matrix matrix = t.getMatrix();
        mCamera.save();
        // 使用Camera设置Y轴方向的旋转角度
        mCamera.rotateY(mRotateY * interpolatedTime);
        // 将旋转变化作用到matrix上
        mCamera.getMatrix(matrix);
        mCamera.restore();
        // 通过pre方法设置矩阵作用前的偏移量来改变旋转中心
        matrix.preTranslate(mCenterWidth, mCenterHeight);// 在旋转之前开始位移动画
        matrix.postTranslate(-mCenterWidth, -mCenterHeight);// 在旋转之后开始位移动画
    }
}

下面是电视机关机画面和图片3D旋转动画的测试类, CustomAniTest 代码如下!

package com.wondertwo.custom;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

import com.wondertwo.R;

/**
 * 自定义动画测试类
 * Created by wondertwo on 2016/3/13.
 */
public class CustomAniTest extends Activity {

    private boolean flag = true;// 标记位,轮换展示两种自定义动画

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_ani);
    }

    /**
     * 设置按钮点击事件
     */
    public void startCustomAni(View view) {
        if (flag) {
            TVCloseAni tvAni = new TVCloseAni();
            view.startAnimation(tvAni);
            // 重置标记位
            flag = false;
        } else {
            CustomAni customAni = new CustomAni();
            customAni.setRotateY(30);
            view.startAnimation(customAni);
            // 重置标记位
            flag = true;
        }
    }
}

唯一不同的是在上面3D旋转自定义动画中,我们引入了 Camera 的概念, android.graphics.Camera 中的 Camera 类封装了 openGL 的3D动画,因此可以通过 Camera 类实现很多酷炫的3D动画效果。


【总结】本文主要介绍了下列内容:

  1. Android动画的基本概念
  2. 视图动画的基本用法
  3. 视图动画的组合用法
  4. 自定义View动画

如果觉得不错,请继续关注哦!下一篇将继续介绍Android属性动画哈!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值