Android开发之Frame动画(帧动画)

学必求其得,业必贵其专精。——章学成

我们学习的根本是懂得怎样为人处世,而对于我们的专业一定要坚持不懈的学习让其达到精益求精的地步,这样我们才能在这个技术层出不穷的社会上立足,前进。

 接下来就进入正题 如有谬误欢迎批评指正,如有疑问欢迎留言,谢谢。  

今天我们就来学习一下Android中的Frame动画,在学习这些基础的东西我们一定要参考谷歌给我们的文档,因为谷歌的文档是最权威的讲解。官网给出的Frame Animation动画的定义

Frame动画:包含一个接一个的将要显示的图片资源,这是一个传统的动画,它创建一个不同的图像序列,有顺序 的播放,就像一卷胶卷,我们称为帧动画。

从官网给出的定义我们不难看出其实Frame 动画就是一系列的图片的按照指定的顺序播放的过程,Frame动画可以被定义在XML中也可以,在代码中来实现。如果定义在XML中我们可以放在res/drawable/filename.xml或者res/anim/finename.xml,如果完全由代码实现的话,就要用到AnimationDrawable对象。
1.将动画定义在XML中官网给出的定义如下
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot=["true" | "false"] >
    <item
        android:drawable="@[package:]drawable/drawable_resource_name"
        android:duration="integer" />
</animation-list>
标签及属性说明:
<animation-list>必须元素,包含一个或多个<item>元素.
<android:oneshot> boolean类型.  如果为true则动画只播放一次,如果为false则循环播放动画,如果不设置则默认为fasle.
<item> 一帧动画,必须有一个<animation-list>父节点.
<item>节点中的属性android:drawable此帧动画所对应的图片资源,android:duration此帧动画播放所需要的时间,单位为毫秒。
在说帧动画的例子之前之前我们来说一下使用帧动画所需注意的事项
官网中明确指出在调用AnimationDrawable.start()方法时不能在Activity的onCreate()方法中调用,因为AnimationDrawable的start方法时,窗口Window对象还没有完全初始化,AnimationDrawable不能完全追加到窗口Window对象中,那我们怎么解决这个问题呢?官网给出的建议是在Activity的onWindowFocusChanged方法(如果对此方法不熟可以看此博客http://blog.csdn.net/dmk877/article/details/45059261)中去掉用AnimationDrawable.start()方法,因为onWindowFocusChanged在Activity窗口获得或失去焦点时调用,例如创建时首次展示在用户面前,所以在调用onWindowFocusChanged方法时窗口已经初始化完全了。但是经过测试发现在以上所说的只是针对较低版本,我用的Android 2.3.3的版本对以上进行测试发现当在onCreate方法中调用AnimationDrawable.start()方法时动画会停留在第一帧,并没有看到我们想要的效果。而当我把AnimationDrawable.start()方法放到onWindowFocusChanged下时动画是正常播放的,但是如果是运行在Android 4.1.2的模拟器上时会发现即使在onCreate方法中调用AnimationDrawable.start()方法动画显示也是正常的,所以为了安全起见我们最好将AnimationDrawable.start()方法放在onWindowFocusChanged方法中。
(1)将动画定义在XML中
下面我们就结合实例来做一个像下面的动画
技术分享
首先在res下新建一个anim的文件夹在此文件夹下新建一个frame.xml文件,frame.xml文件的内容如下
<? xml version= "1.0" encoding= "utf-8" ?> 
<animation-list xmlns:android ="http://schemas.android.com/apk/res/android"  
    android:oneshot= "false">  
    <item   android:drawable ="@drawable/qb_tenpay_loading_1"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_2"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_3"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_4"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_5"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_6"  android:duration ="100" />  
    <item   android:drawable ="@drawable/qb_tenpay_loading_7"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_8"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_9"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_10"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_11"  android:duration ="100" />
    <item   android:drawable ="@drawable/qb_tenpay_loading_12"  android:duration ="100" />
</animation-list>
然后布局
<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"
    android:orientation= "horizontal"
    tools:context= ".MainActivity" >
    <Button
        android:id= "@+id/btn_play"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:text ="启动动画" />
    <Button
        android:id= "@+id/btn_stop"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:layout_toRightOf= "@id/btn_play"
        android:text ="停止动画"/>
    <ImageView
        android:id= "@+id/iv_image"
        android:layout_width= "wrap_content"
        android:layout_height= "wrap_content"
        android:layout_centerInParent ="true"
        android:background= "@anim/frame" />
</RelativeLayout>
假如我们把AnimationDrawable.start()方法放在onCreate方法下如下
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
      private AnimationDrawable anim;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
       
        btnPlay=(Button) findViewById(R.id. btn_play);
        ivImage=(ImageView) findViewById(R.id. iv_image);
        btnStop=(Button) findViewById(R.id. btn_stop);
       
        ivImage.setBackgroundResource(R.anim. frame);
        anim = (AnimationDrawable) ivImage.getBackground();
        anim.start();
     
        setClickListener();
    }

      private void setClickListener() {
            btnStop.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.stop();
                }
           });
       
        btnPlay.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.start();
                }
           });
     }
}
然后运行在Android 2.3.3的模拟器上发现次动画只停留在第一帧,但是当我们点击启动动画按钮时动画会正常的播放(因为此时windows窗口已经完全初始化),然后我们代码不变将此工程运行在高版本上,我是运行在Android 4.1.2的模拟器上的,发现动画是正常播放的(并没有停留在第一帧)。但是为了兼容性更好,更安全我们最好将启动动画的代码写在onWindowFocusChanged方法中,代码如下
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
     private AnimationDrawable anim;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
      
        btnPlay=(Button) findViewById(R.id. btn_play);
        ivImage=(ImageView) findViewById(R.id. iv_image);
        btnStop=(Button) findViewById(R.id. btn_stop);
       
        setClickListener();
    }
     
      private void setClickListener() {
            btnStop.setOnClickListener( new OnClickListener() {
               
                 @Override
                 public void onClick(View v) {
                      //停止播放动画
                     anim.stop();
                }
           });
      
        btnPlay.setOnClickListener( new OnClickListener() {
               
                 @Override
                 public void onClick(View v) {
                       //开始播放动画
                      anim.start();
                }
         });
     }
    @Override
     public void onWindowFocusChanged( boolean hasFocus) {
     super.onWindowFocusChanged(hasFocus);
     //将背景设置为动画
     ivImage.setBackgroundResource(R.anim. frame);
     anim = (AnimationDrawable) ivImage.getBackground();
     //启动动画
     anim.start();
   }
}
这样无论在高版本还是低版本动画的播放都是正常的。另外除了将
ivImage.setBackgroundResource(R.anim. frame);
 anim = (AnimationDrawable) ivImage.getBackground();
 anim.start();
这些代码放在onWindowFocusChanged方法中之外还有一种解决方法通过开启一个子线程的方式如
ivImage.post( new Runnable() { 
            @Override 
            public void run() { 
                 anim.start(); 
            } 
        });
此时工程的代码如下
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
      private AnimationDrawable anim;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
        btnPlay=(Button) findViewById(R.id. btn_play);
        ivImage=(ImageView) findViewById(R.id. iv_image);
        btnStop=(Button) findViewById(R.id. btn_stop);
       
       
        ivImage.setBackgroundResource(R.anim. frame);
        anim = (AnimationDrawable) ivImage.getBackground();
        ivImage.post( new Runnable() { 
            @Override 
            public void run() { 
                 anim.start(); 
            } 
        }); 
        setClickListener();
    }

      private void setClickListener() {
            btnStop.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.stop();
                }
           });
       
        btnPlay.setOnClickListener( new OnClickListener() {
                
                 @Override
                 public void onClick(View v) {
                      anim.start();
                }
           });
     }   
}
这种可以也可以同时在低和高版本中运行。
(2)完全由代码实现动画
完全通过代码和定义在xml中是类似的只不过将xml中的属性或者标签通过代码的形式来定义
package com.example.animationpractice;

import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

     Button btnPlay;
     ImageView ivImage;
     Button btnStop;
      private AnimationDrawable anim;
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout. activity_main);
        ivImage=(ImageView) findViewById(R.id. iv_image);
       
        anim = new AnimationDrawable(); 
        for ( int i = 1; i <=12; i++) {
            //根据资源名称和目录获取R.java中对应的资源ID 
            int id = getResources().getIdentifier("qb_tenpay_loading_" + i, "drawable" , getPackageName()); 
            //根据资源ID获取到 Drawable对象 
            Drawable drawable = getResources().getDrawable(id); 
            //将此帧添加到AnimationDrawable中 
            anim.addFrame(drawable,100); 
        } 
        //设置循环播放
        anim.setOneShot( false); 
        //设置图片的背景为我们的动画
        ivImage .setBackgroundDrawable (anim);
 
    }
   
    @Override
    public void onWindowFocusChanged( boolean hasFocus) {
      super.onWindowFocusChanged(hasFocus);
      //启动动画
      anim.start();
    }   
}
同样我们需要注意将start()方法不要在窗口初始化的时候调用就行了。

如有谬误欢迎批评指正,如有疑问欢迎留言谢谢。






郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。