首页 > 代码库 > Android API Demos 系列之 — 播放GIF动画的类Movie

Android API Demos 系列之 — 播放GIF动画的类Movie

良好的开端,是成功的一半。A good beginning is half done.  -_-

本文目录

  ● 一、什么是GIF

   二、Android系统和应用如何播放GIF

 

一、【什么是GIF】

  Gif动态图片,是通过对多图层的图片,按时间进行不同的切换,以达到动画的效果。Gif动态图片的特点是,图片小,易于随时安置调用。比起一张单调的静态图片,Gif格式的动态图片明显更加的生动和有意思。

二、【Android系统和应用如何播放GIF】

  在Android系统的原生控件ImageView并不支持播放GIF格式的动态图片。那么Android系统和应用是如何播放Gif格式的动态图片呢?让我们一块去翻看一下Android的API Demos。

  在Android 系统(android-17)提供的API Demos列表—>Graphics—>BitmapDecode界面中,我们可以看到一幅飘杨的旗帜,正是API Demos为我们提供的播放Gif动态图片的示例。对应AndroidADT—>sdk—>samples—>android-17—>ApiDemos中graphics包下的BitmapDecode.java类。

  技术分享

  图1 API Demos Gif动态图示例

  接下来,去翻看一下BitmapDecode.java类的源码。从其中分离出来的相关源码并整理如下:

  1. Copy API Demos源码,自定义实现能够播放Gif动态图片的控件GifMovieView.java

package com.lzz.gifmovie;import java.io.BufferedInputStream;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import android.content.Context;import android.graphics.Canvas;import android.graphics.Movie;import android.os.Environment;import android.os.SystemClock;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.widget.Toast;/** * 自定义控件实现播放Gif动态图片 * @author lzz * Movie.decodeByteArray(data, offset, length); * Movie.decodeStream(is); * Movie.decodeFile(pathName); //这个方法不能正常显示Gif,需要指定BufferSize * You need to use InputStream with a BufferSize while loading .GIF images From SDCARD.  * It‘ll work for sure. */public class GifMovieView extends View {    private static final String TAG = GifMovieView.class.getSimpleName();    private static final String externalPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;    /**     * 这个类目前文档没有API官方说明     */    private Movie mMovie;     /**     * 记录起始时间      */    private long mMovieStart;    /**     * gif图片文件名(包含后缀.gif)     */    private String gifFileName;    /**     * gif图片所在项目的资源id     */    private int gifResourceId;    public GifMovieView(Context context) {        super(context);        System.out.println("第1个构造方法");        this.gifResourceId = R.drawable.animated_gif;        this.gifFileName = "giftest1.gif";                playGifImage(gifResourceId);        playGifImage(this.gifFileName);            }        public GifMovieView(Context context, AttributeSet attrs) {        super(context, attrs);        Log.i(TAG, "第2个构造方法");                this.gifResourceId = R.drawable.animated_gif;        this.gifFileName = "giftest2.gif";                playGifImage(gifResourceId);        playGifImage(gifFileName);    }        public GifMovieView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        Log.i(TAG, "第3个构造方法");                this.gifResourceId = R.drawable.animated_gif;        this.gifFileName = "giftest3.gif";                playGifImage(gifResourceId);        playGifImage(gifFileName);            }            /**     * 设置所要播放的gif图片的文件名     * @param gifFileName     */    public void playGifImage(String gifFileName) {        this.gifFileName = gifFileName;        File file = new File(externalPath + gifFileName);        System.out.println("gif文件路径: "+ externalPath + gifFileName);        if(file.exists()){            InputStream inputStream = null;            try {                inputStream = new BufferedInputStream(new FileInputStream(file));                byte[] array = streamToBytes(inputStream);                mMovie = Movie.decodeByteArray(array, 0, array.length);            } catch (FileNotFoundException e) {                e.printStackTrace();            } finally {                if(null != inputStream){                    try {                        inputStream.close();                    } catch (IOException e) {                        e.printStackTrace();                    }                }            }        }else{            Toast.makeText(this.getContext(), "所要播放的gif图片不存在", Toast.LENGTH_LONG).show();        }    }        /**     * 把流转换成byte[]     * @param is 输入流     * @return 字节数组     */    private static byte[] streamToBytes(InputStream is) {        ByteArrayOutputStream os = new ByteArrayOutputStream(1024);        byte[] buffer = new byte[1024];        int len;        try {            while ((len = is.read(buffer)) >= 0) {                os.write(buffer, 0, len);            }        } catch (java.io.IOException e) {        }        return os.toByteArray();    }            /**     * 设置所要播放的gif图片资源id     * @param id     */    public void playGifImage(int id) {        if(0 != id){            this.gifResourceId = id;            InputStream inputStream = this.getResources().openRawResource(id);            mMovie =  Movie.decodeStream(inputStream);        }else{            Toast.makeText(this.getContext(), "所要播放的gif图片不存在", Toast.LENGTH_LONG).show();        }    }    /**     * 重载onDraw()方法,实现gif图片的逐帧播放     */    @Override    protected void onDraw(Canvas canvas) {        long now = SystemClock.uptimeMillis(); // 当前时间        if(0 == mMovieStart){ // 如果第一帧,记录起始时间            mMovieStart = now;        }                if(null != mMovie){            int mDuration = mMovie.duration(); // 取出动画的时长            if(0 == mDuration){                mDuration = 1000;            }            // 算出需要显示第几帧            int realTime = (int)((now - mMovieStart) % mDuration);            mMovie.setTime(realTime); // 需要显示的帧,绘制即可            mMovie.draw(canvas, getWidth() - mMovie.width(), getHeight() - mMovie.height());            invalidate();                    }    }    }

 

  2. GifMovieActivity的布局文件activity_gif_movie.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:id="@+id/container"    android:orientation="vertical" >    </LinearLayout>

 

  3. GifMovieActivity.java代码   

package com.lzz.gifmovie;import android.annotation.SuppressLint;import android.app.ActionBar.LayoutParams;import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.util.DisplayMetrics;import android.view.Gravity;import android.widget.LinearLayout;/** * 测试播放Gif动态图片的自定义控件GifMovieView * @author lzz *  */@SuppressLint("NewApi") public class GifMovieActivity extends ActionBarActivity {        @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_gif_movie);                // 获取屏幕的宽高        DisplayMetrics displayMetrics = new DisplayMetrics();        this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);        int screenWidth = displayMetrics.widthPixels;        int screenHeight = displayMetrics.heightPixels;        System.out.println("手机屏幕分辨率为:" + screenWidth +"*" + screenHeight);                LayoutParams params1 = new LayoutParams(            LayoutParams.WRAP_CONTENT, screenHeight/3 );        params1.gravity = Gravity.CENTER;                // 添加一个自定义的GifMovieView控件        GifMovieView gifMovieView1 = new GifMovieView(this);        gifMovieView1.setLayoutParams(params1);        gifMovieView1.playGifImage(R.drawable.animated_gif);                LayoutParams params2 = new LayoutParams(            LayoutParams.WRAP_CONTENT, screenHeight/2 );        params2.gravity = Gravity.CENTER;                GifMovieView gifMovieView2 = new GifMovieView(this);        gifMovieView2.setLayoutParams(params2);        gifMovieView2.playGifImage("giftest1.gif");                // 往自定义控件上添加前面自定义的两个控件GifMovieView        LinearLayout linearLayout = (LinearLayout) findViewById(R.id.container);        linearLayout.addView(gifMovieView1);        linearLayout.addView(gifMovieView2);            }    }

 

 

 

  4. 重点记得在AndroidManifest.xml文中的<application>或者有播放Gif动态图的<activity>结点中

  加入:android:hardwareAccelerated="false" 这一行代码。

<application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name="com.lzz.gifmovie.GifMovieActivity"            android:hardwareAccelerated="false"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application>

  5. 有图有真相:

  技术分享

  图2 自定义控件GifMovieView播放Gif动态图片效果

 

Android API Demos 系列之 — 播放GIF动画的类Movie