Android动画之View动画与帧动画

声明:本篇文章主要是学习《Android开发艺术与探索》时做的学习笔记。

概述

Android动画可分为三种:View动画丶帧动画和属性动画,其实帧动画也属于View动画的一种,只不过它和平移丶旋转等常见的View动画在表现形式上略有不同而已。
1. View动画通过对场景里的对象不断做图像变换(平移丶缩放丶旋转丶透明度)从而产生动画效果,是一种渐进式动画,并且View动画支持自定义。
2. 帧动画则是通过顺序播放一系列图像从而产生动画效果,可以简单理解为图片切换动画,很显然,帧动画如果图片过多过大会导致OOM。
3. 属性动画通过动态改变对象的属性从而达到动画效果,属性动画是API 11的新特性,在低版本无法直接使用属性动画,但是我们依然可以通过兼容库来使用它。

一丶View动画

View动画的作用对象是View,支持4中动画效果:平移丶缩放丶旋转和透明度动画。
View动画的四种变换效果对应着Animation的四个子类:TranslateAnimation丶ScaleAnimation丶RotateAnimation和AlphaAnimation。对于View动画,可以通过代码动态创建,也可通过XML来定义,建议采用XML来定义View动画,因为XML格式的动画可读性好。

1. View动画的使用

首先在res/anim/下创建动画XML文件,View动画的描述语法一般都是固定的,具体如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:shareInterpolator="true">
    <alpha
        android:duration="2000"
        android:fromAlpha="0"
        android:toAlpha="1" />
    <scale
        android:duration="2000"
        android:fromXScale="0"
        android:toXScale="1"
        android:fromYScale="0"
        android:toYScale="1"
        android:pivotX="50%"
        android:pivotY="50%" />
    <translate
        android:duration="2000"
        android:fromXDelta="0"
        android:toXDelta="100"
        android:fromYDelta="0"
        android:toYDelta="100"/>
    <rotate
        android:duration="2000"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%" />
</set>

上面的动画是一个动画集合,当然也可以只有单个动画。标签表示动画集合,对应的是AnimationSet类,它可以包含若干个动画,并且它的内部也是可以嵌套其他动画集合的。需要注意的是android:pivotX属性一般指定为百分比,50%则表示在其中心点的位置。

并且,对于标签,它有两个比较重要的属性:

android:interpolator

表示动画集合所采用的插值器,插值器影响动画的速度,比如非匀速动画就需要插值器来控制动画的播放过程。这个属性可以不指定,默认为@android:anim/accelerate_decelerate_interpolator,即加速减速插值器。

android:shareInterpolator

表示集合中的动画是否和集合共享同一个插值器。如果集合不指定插值器,那么子动画就需要单独制定所需要的插值器或者使用默认值。

要使用上面XML定义的动画,代码如下:

        ImageView mImageView = (ImageView) findViewById(R.id.mImageView);
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_view);
        mImageView.startAnimation(animation);

并且除了在XML中定义动画,还可以通过代码的形式来应用动画,比如想要将一张图片的透明度在2000ms内从0变为1,具体代码如下(想要实现其他动画类似):

        ImageView mImageView = (ImageView) findViewById(R.id.mImageView);
        AlphaAnimation animation = new AlphaAnimation(0,1);
        animation.setDuration(2000);
        mImageView.startAnimation(animation);

2. View动画的监听器

通过Animation的setAnimationListener方法可以给View动画添加过程监听,下面是具体的代码演示:

animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                Log.e("TAG","动画开始");
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.e("TAG","动画结束");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.e("TAG","动画重新开始播放");
            }
        });

3. View动画的特殊使用场景

①LayoutAnimation

LayoutAnimation作用于ViewGroup,为ViewGroup指定一个动画,这样当它的子元素出场也会具有这种动画效果。这种效果常用于ListView上,那么我们的ListView的item都会以一定的动画形式出现。LayoutAnimation也是一个View动画,为了给ViewGroup的子元素添加出场效果,遵循以下几步:
(1)在定义LayoutAnimation,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.5"
    android:animationOrder="normal"
    android:animation="@anim/anim_view">
</layoutAnimation>

LayoutAnimation有几个比较重要的属性:

android:delay

表示子元素开始动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5就代表每个子元素都需要延迟150ms才能播放入场动画。总体来说,第一个子元素延迟150ms开始播放入场动画,第二个子元素延迟300ms开始播放入场动画,依次类推。

android:animationOrder

表示子元素动画的顺序,有三种选项:nomal丶reverse丶和random,其中normal表示顺序显示,reverse表示逆向显示,random则表示随机播放入场动画。

android:animation

为子元素指定具体的入场动画。

(2)为子元素指定具体的入场动画,如下所示:
在res/anim/anim_view

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:shareInterpolator="true">
    <alpha
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <translate
        android:fromXDelta="500"
        android:toXDelta="0"/>
</set>

(3)为ViewGroup指定android:layoutAnimation属性:android:layoutAnimation=”@anim/anim_layout”。对于ListView来说,这样ListView的item就具有出场动画了,这种方式适用于所有ViewGroup,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <ListView
        android:id="@+id/mListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutAnimation="@anim/anim_layout"/>
</RelativeLayout>

到这里,LayoutAnimation的用法基本已经讲完,为了更好的体现它的效果,这里我写了一个小Demo,具体的布局文件都采用的是上面步骤里的,这里只贴MainActivity的代码:

  • MainActivity
package com.wangjian.annimationtest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;


public class MainActivity extends Activity {

    private ListView mListView;
    private int[] listData = {R.mipmap.a1,R.mipmap.a2,R.mipmap.a3,R.mipmap.a4,R.mipmap.a5,R.mipmap.a6,};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.mListView);
        mListView.setAdapter(new MyAdapter());
    }

    class MyAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return listData.length;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if(convertView == null){
                convertView = View.inflate(MainActivity.this, R.layout.item, null);
                holder = new ViewHolder();
                holder.imageView = (ImageView) convertView.findViewById(R.id.image);
                convertView.setTag(holder);
            }else{
                holder = (ViewHolder) convertView.getTag();
            }
            holder.imageView.setBackgroundResource(listData[position]);
            return convertView;
        }
    }

    class ViewHolder{
        ImageView imageView;
    }
}

代码很简单,就是给ListView的每个item填充一张图片,并且采用ViewHolder进行了复用操作。

运行结果如下:
这里写图片描述

通过运行结果我们会发现一个问题,那就是后面几张图片并没有入场动画,原因很简单,是因为与ListView的复用之间的冲突,由于它们是被复用的,出场动画在之前已经播放过了。目前我还没有找到比较好的解决方案,已经解决了的同学还望留言分享一下,或者采用其他方式去实现。

除了在XML中指定LayoutAnimation外,还可以通过LayoutAnimationController来实现,具体代码如下:

 mListView = (ListView) findViewById(R.id.mListView);
        Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_view);
        LayoutAnimationController controller = new LayoutAnimationController(animation);
        controller.setDelay(0.5f);
        controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
        mListView.setLayoutAnimation(controller);
②实现Activity和Fragment的切换效果

Activity之间的切换效果主要用到overridePendingTransition(int enterAnim, int exitAnim)方法,并且这个方法必须在startActivity(intent)或者finish()之后调用才能生效。

enterAnim:Activity被打开时,所需要的动画资源id;
exitAnim:Activity被暂停时,所需要的动画资源id。

并且Fragment也可以添加切换动画,由于Fragment是在API 11中新引入的类,因此我们一般使用support-v4这个兼容包。要为Fragment也可以添加切换动画,主要通过FragmentTransaction中的setCustomAnimations()方法来添加切换动画。这个切换动画需要是View动画,之所以不能采用属性动画是因为属性动画也是API 11新引入的,会有兼容性的问题。

二丶 帧动画

帧动画是顺序播放一组预先定义好的图片,类似于电影的播放。不同于View动画,系统提供了另外一个类AnimationDrawable来使用帧动画。要使用帧动画,首先需要在res/drawable/通过XML文件来定义一个AnimationDrawable,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@mipmap/a1" android:duration="500" />
    <item android:drawable="@mipmap/a2" android:duration="500" />
    <item android:drawable="@mipmap/a3" android:duration="500" />
    <item android:drawable="@mipmap/a4" android:duration="500" />
    <item android:drawable="@mipmap/a5" android:duration="500" />
    <item android:drawable="@mipmap/a6" android:duration="500" />
</animation-list>

然后将上述的Drawable作为View的背景并通过Drawable来播放动画即可:

 ImageView mImageView = (ImageView) findViewById(R.id.mImageView);
        mImageView.setBackgroundResource(R.drawable.animdrawable);
        AnimationDrawable drawable = (AnimationDrawable) mImageView.getBackground();
        drawable.start();

帧动画使用简单,其中 android:oneshot代表帧动画的自动执行, 如果为true,表示动画只播放一次停止在最后一帧上,如果设置为false表示动画循环播放。帧动画容易造成OOM,所以在使用时应尽量避免使用过多尺寸较大的图片。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值