Android 动画——视图动画(补间动画+帧动画)

    Android 动画主要可以分为两种,一种就是视图动画,一种就是属性动画,这里我们先了解一下视图动画。

    而视图动画也分为 Tween(补间)动画和 Frame(帧)动画。

  • 补间动画

    补间动画就是一个 View 从开始状态到结束状态变化的过程,补间动画有四种基本变化:渐变、平移、缩放、旋转,这四种基本动画效果都可以通过 xml 和代码两种方式来实现。补间动画如果要使用 xml 方法,就需要在 res 文件目录下创建 anim文件夹,将动画的 xml 文件放在其中:


    xml 主要共有熟悉:

属性名  说明
android:duration=""  动画持续时间,单位:毫秒
android:startOffset=""  动画开始时间,单位:毫秒

  • 渐变动画
  • xml 方法

    xml 方法主要属性:

属性名  说明
android:fromAlpha=""  动画开始时透明度,0.0 表示全透明,1.0 表示不透明
android:toAlpha="" 动画结束时透明度,0.0 表示全透明,1.0 表示不透明

    代码:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration="1000"/>
</set>
 // 通过 xml 完成渐变动画
    private void doAlphaByXML(){
        Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_tween_alpha);
        image.startAnimation(animation);
    }

  • 代码方法
// 通过代码完成渐变动画
    private void doAlphaByCode(){
        AlphaAnimation animation = new AlphaAnimation(1.0f,0.0f);
        animation.setDuration(1000);
        image.startAnimation(animation);
    }
  • 平移动画
  • xml 方法
    xml 方法主要属性:
属性名  说明
android:fromXDelta="" X 轴开始地方,0表示自身 X 坐标,单位:像素
android:fromYDelta="" Y 轴开始地方,0表示自身 Y 坐标,单位:像素
android:toXDelta="" X 轴结束地方,0表示自身 X 坐标,单位:像素
android:toYDelta="" Y 轴结束地方,0表示自身 Y 坐标,单位:像素

   代码:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="5"
        android:toXDelta="100"
        android:fromYDelta="0"
        android:toYDelta="100"
        android:duration="1000"
        />
</set>
// 通过 xml 完成平移动画
    private void doTranslateByXML(){
        Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_tween_translate);
        image.startAnimation(animation);
    }
  • 代码方法
// 通过代码完成平移动画
    private void doTranslateByCode(){
        TranslateAnimation animation = new TranslateAnimation(0,100,0,100);
        animation.setDuration(1000);
        image.startAnimation(animation);
    }
   前提说明,因为缩放动画和旋转动画的 xml 属性,以及代码方法的参数有共同之处,这里先做一个说明。
属性名  说明
android:pivotX=""  缩放或者旋转时的中心点的 X 坐标
android:pivotY=""  缩放或者旋转时的中心点的 Y 坐标

  • 缩放动画
  • xml 方法
    xml 方法主要属性:
属性名  说明
android:fromXScale=""  X 轴开始的大小,1 表示自身大小,单位:比例
android:toXScale=""   X 轴结束的大小,1 表示自身大小,单位:比例
android:fromYScale=""  Y 轴开始的大小,1 表示自身大小,单位:比例
android:toYScale=""   Y 轴结束的大小,1 表示自身大小,单位:比例

    代码:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:fromXScale="0.5"
        android:toXScale="2"
        android:fromYScale="0.5"
        android:toYScale="2"
        android:pivotX="0"
        android:pivotY="0"
        android:duration="1000"/>
</set>
// 通过 xml 完成缩放动画
    private void doScaleByXML(){
        Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_tween_scale);
        image.startAnimation(animation);
    }
  • 代码方式
// 通过代码完成缩放动画
    private void doScaleByCode(){
        ScaleAnimation animation = new ScaleAnimation(0.5f,2,0.5f,2,0,0);
        animation.setDuration(1000);
        image.startAnimation(animation);
    }
  • 旋转动画
  • xml 方法

    xml 方法主要属性:

属性名

 说明

android:fromDegrees=""  动画开始的角度,单位:度(正从顺时针)
android:toDegrees=""  动画结束的角度,单位:度(正从顺时针)
     代码:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:duration="1000"
        android:pivotX="100%"
        android:pivotY="100%"/>
</set>
// 通过 xml 完成旋转动画
    private void doRotateByXML(){
        Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_tween_rotate);
        image.startAnimation(animation);
    }

    注意:android:pivotX="" 和 android:pivotY="" 有三种方式,如下(以 android:pivotX="" 举例),三种方式的坐标原点都是以自身 View 的左上角。

方式  结果
android:pivotX="100"(float 方式)  以像素为大小
android:povotX="50%"(百分比方式)  以自身为大小,指占比自己大小多少
android:prvotX="50%p"(百分比 p 方式)  以页面为大小,指占比页面多少

    这个,可能文字描述起来比较抽象,大家写一下马上就能明白

  • 代码方法
// 通过代码完成旋转动画
    private void doRotateByCode(){
        RotateAnimation animation = new RotateAnimation(0,360,100,100);
        animation.setDuration(1000);
        image.startAnimation(animation);
    }

    注意:旋转和缩放动画使用代码方式时,其不止一个构造方法,文中,写的构造方法是没有 pivotXType 和 pivotYType 的,没有选 Type,默认为像素。

  • 组合动画

     当然,我们使用动画时,不可能只使用一种动画,我们只有组合使用,才能达到一些想要的动画效果:

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

    <translate
        android:fromXDelta="0"
        android:toXDelta="100"
        android:fromYDelta="0"
        android:toYDelta="100"
        android:duration="1000"/>
    <rotate
        android:pivotX="-100"
        android:pivotY="-100"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:duration="2000"
        android:startOffset="1000"/>
    <rotate
        android:pivotX="50%"
        android:pivotY="50%"
        android:fromDegrees="0"
        android:toDegrees="720"
        android:duration="2000"
        android:startOffset="1000"/>
    <scale
        android:fromXScale="1"
        android:toXScale="3"
        android:fromYScale="1"
        android:toYScale="3"
        android:pivotX="0"
        android:pivotY="0"
        android:duration="2000"
        android:startOffset="3000"/>
    <alpha
        android:fromAlpha="1.0"
        android:toAlpha="0.0"
        android:duration="2000"
        android:startOffset="3000"/>
</set>

    是时候放一波效果图了:


    大家可以看到,视图动画结束后会默认回到原来的位置,我们可以使用该函数,让其动画结束后留在原地:

        animation.setFillAfter(true);

     注意:视图动画有一个致命缺点,就是视图动画动的只是它的外表,它的坐标并没有随着外表动而动,这是什么意思呢?就是当一个视图动画结束后并且留在动画结束后的位置时,其是不能响应点击事件的,而点击动画原来的位置,却发现其响应了点击事件,大家可以试试。

    那这个问题怎么解决呢?比较暴力的方法,就是写两个 View,新的 View 放在动画结束的位置,旧的 View 在动画结束后消失,并且让其不可被点击,显示新的 View,然后响应新的 View 的点击事件。

    还有什么办法呢?就是使用 Android 3.0 后的属性动画,属性动画移动的不仅是外表,还有其属性,这个问题就可以完美解决。

     当然,动画也是有监听器的:

animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                // 动画开始时
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                // 动画结束时
            }

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

  • 帧动画

    帧动画又是什么意思呢?大家都知道电影吧,电影是可以取帧的,每一帧就是一张图片,将很多帧组合在一起就成了动画,帧动画就好比将很多张图片连续展示,组成一幅动的画:


    帧动画,现在已经很少使用了,自从 Android 3.0 的属性动画出来以后补间动画都用的少了,这里也来说一说实现补间动画的方式吧。

  • xml 方法
    xml 方法主要属性
属性名  说明
android:drawable=""  当前帧的图片
android:duration=""  当前帧的播放时间,单位:毫秒

    通过 xml 实现帧动画和补间动画是不太一样的,帧动画的 xml 文件是在 drawable 目录下的,并且以 <animation-list> 为根节点。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/frame1" android:duration="50"/>
    <item android:drawable="@drawable/frame2" android:duration="50"/>
    <item android:drawable="@drawable/frame3" android:duration="50"/>
    <item android:drawable="@drawable/frame4" android:duration="50"/>
    <item android:drawable="@drawable/frame5" android:duration="50"/>
    <item android:drawable="@drawable/frame6" android:duration="50"/>
    <item android:drawable="@drawable/frame7" android:duration="50"/>
    <item android:drawable="@drawable/frame8" android:duration="50"/>
    <item android:drawable="@drawable/frame9" android:duration="50"/>
    <item android:drawable="@drawable/frame10" android:duration="50"/>
    <item android:drawable="@drawable/frame11" android:duration="50"/>
    <item android:drawable="@drawable/frame12" android:duration="50"/>
    <item android:drawable="@drawable/frame13" android:duration="50"/>
    <item android:drawable="@drawable/frame14" android:duration="50"/>
    <item android:drawable="@drawable/frame15" android:duration="50"/>
    <item android:drawable="@drawable/frame16" android:duration="50"/>
    <item android:drawable="@drawable/frame17" android:duration="50"/>
    <item android:drawable="@drawable/frame18" android:duration="50"/>
    <item android:drawable="@drawable/frame19" android:duration="50"/>
    <item android:drawable="@drawable/frame20" android:duration="50"/>
    <item android:drawable="@drawable/frame21" android:duration="50"/>
    <item android:drawable="@drawable/frame22" android:duration="50"/>
    <item android:drawable="@drawable/frame23" android:duration="50"/>
    <item android:drawable="@drawable/frame24" android:duration="50"/>
    <item android:drawable="@drawable/frame25" android:duration="50"/>

</animation-list>
// 通过 xml 实现帧动画
    private void doFrameByXML(){
        imageView.setBackgroundResource(R.drawable.anim_frame);
        AnimationDrawable drawable = (AnimationDrawable) imageView.getBackground();
        if (!drawable.isRunning()){
            drawable.start();
        }
    }

代码方法:

// 通过代码实现帧动画
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    private void doFrameByCode(){
        AnimationDrawable drawable = new AnimationDrawable();
        drawable.addFrame(getResources().getDrawable(R.drawable.frame1),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame2),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame3),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame4),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame5),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame6),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame7),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame8),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame9),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame10),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame11),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame12),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame13),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame14),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame15),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame16),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame17),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame18),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame19),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame20),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame21),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame22),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame23),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame24),50);
        drawable.addFrame(getResources().getDrawable(R.drawable.frame25),50);
        imageView.setBackground(drawable);
        // 是否只播放一次
        drawable.setOneShot(false);
        if (!drawable.isRunning()){
            drawable.start();
        }
    }

    效果图:


    大家需要注意的是,如果是自己测试做帧动画,一定要注意图片不能太大,不能过多,要不然会造成突然加载大量图片导致 OOM。

    项目地址:源代码

猜你喜欢

转载自blog.csdn.net/Young_Time/article/details/80839988