Gif ImageView的实现

在android里,imageview 只能显示静态图片,但是有时候我们需要播放gif图片,如何实现呢。唯一的办法就是重写imageview了。

在进行前,我们引入一个知识点。Moive类,这个类能够播放gif动画。

通过不断设置setTime就能播放其中的某一帧,然后不断调用 

invalidate();
便能够强制重绘空间,达到一种播放的效果
 
///
实现:
 
首先我们要重写ImageView
 
在values下创建一个新的属性文件:名为attrs
 
创建如下属性:
 
<?xml version="1.0" encoding="utf-8"?>

<resources>

    <declare-styleable name="GifImageView">
        <attr name="auto_play" format="boolean"></attr>
    </declare-styleable>

</resources>
auto_play为一个是否支持自动播放的属性 类型为布尔
 
然后创建自己的类,在构造函数中进行扫描属性,如果有android:src属性 那么就认为用户要播放一个gif,如果还找到auto_play属性 那么还认为这个gif要自动播放而不是用户点击了控件才播放gif
 
代码:
 
package com.chan.gitimageview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

import java.io.InputStream;

/**
 * Created by chan on 2015-06-27.
 */
public class GifImageView
        extends ImageView
        implements View.OnClickListener{
    
    /**
     * 播放GIF动画的关键类
     */
    private Movie m_movie;

    /**
     * 开始播放按钮图片
     */
    private Bitmap m_startButton;

    /**
     * 记录动画开始的时间
     */
    private long m_movieStart;

    /**
     * GIF图片的宽度
     */
    private int m_imageWidth;

    /**
     * GIF图片的高度
     */
    private int m_imageHeight;

    /**
     * 图片是否正在播放
     */
    private boolean m_isPlaying;

    /**
     * 是否允许自动播放
     */
    private boolean m_isAutoPlay;

    /**
     * PowerImageView构造函数。
     *
     * @param context
     */
    

    public GifImageView(Context context){
        super(context);
    }

    public GifImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    /**
     * PowerImageView构造函数,在这里完成所有必要的初始化操作。
     *
     * @param context
     */
    public GifImageView(Context context, AttributeSet attrs, int defStyle) {

        super(context, attrs, defStyle);

        int resourceId = 0;

        for(int i = 0;i < attrs.getAttributeCount();++i) {

            if (attrs.getAttributeName(i).equals("src")) {
                resourceId = attrs.getAttributeResourceValue(i, 0);
            }
        }

        if (resourceId != 0) {

            // 当资源id不等于0时,就去获取该资源的流
            InputStream is = getResources().openRawResource(resourceId);

            // 使用Movie类对流进行解码
            m_movie = Movie.decodeStream(is);
           // m_movie = getResources().getMovie(R.drawable.anim);

            if (m_movie != null) {

                TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.GifImageView);
                // 如果返回值不等于null,就说明这是一个GIF图片,下面获取是否自动播放的属性
                m_isAutoPlay = typedArray.getBoolean(R.styleable.GifImageView_auto_play, false);
                typedArray.recycle();

                m_imageWidth = m_movie.width();
                m_imageHeight = m_movie.height();

                if (!m_isAutoPlay) {

                    // 当不允许自动播放的时候,得到开始播放按钮的图片,并注册点击事件
                    m_startButton = BitmapFactory.decodeResource(getResources(),
                            R.drawable.start_play);

                    setOnClickListener(this);
                }
            }
        }
    }

    @Override
    public void onClick(View v) {

        if(v.getId() == getId()){

            m_isPlaying = true;
            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas){

        //如果不是GIF
        if(m_movie == null){
            super.onDraw(canvas);
            return;
        }

        //如果自动播放
        if(m_isAutoPlay){
            playMovie(canvas);
            invalidate();
            return;
        }

        if(m_isPlaying)
        {
            // 正在播放就继续调用playMovie()方法,一直到动画播放结束为止
            if (playMovie(canvas)) m_isPlaying = false;
            invalidate();
        }
        else
        {
            // 还没开始播放就只绘制GIF图片的第一帧,并绘制一个开始按钮
            m_movie.setTime(0);
            m_movie.draw(canvas, 0, 0);

            int offsetW = (m_imageWidth - m_startButton.getWidth()) / 2;
            int offsetH = (m_imageHeight - m_startButton.getHeight()) / 2;

            canvas.drawBitmap(m_startButton, offsetW, offsetH, null);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (m_movie != null) {

            // 如果是GIF图片则重写设定PowerImageView的大小
            setMeasuredDimension(m_imageWidth, m_imageHeight);
        }
    }

    /**
     * 开始播放GIF动画,播放完成返回true,未完成返回false。
     *
     * @param canvas
     * @return 播放完成返回true,未完成返回false。
     */
    private boolean playMovie(Canvas canvas) {

        long now = SystemClock.uptimeMillis();
        if (m_movieStart == 0) {
            m_movieStart = now;
        }

        int duration = m_movie.duration();

        if (duration == 0) {
            duration = 1000;
        }

        int relTime = (int) ((now - m_movieStart) % duration);
        m_movie.setTime(relTime);
        m_movie.draw(canvas, 0, 0);

        if ((now - m_movieStart) >= duration) {
            m_movieStart = 0;
            return true;
        }

        return false;
    }
}
 
HOW TO USE:
<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"  tools:context=".MainActivity"
    xmlns:attr="http://schemas.android.com/apk/res-auto" >


    <com.chan.gitimageview.GifImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        attr:auto_play="false"
        android:src="@drawable/anim"
        android:id="@+id/m_gifImageView" />

</RelativeLayout>


我这里的IDE是android studio  所以第四行那边会有区别 读者根据自己IDE改
 
效果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值