gif格式图片在安卓中的显示(自定义GifView)

在这里主要用的是:android中的android.graphics.Movie 这个类,这是android提供给我们的一个非常方便的工具。

首先,重写控件View,自定义一个展示gif图的GifView,代码如下:

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.Build;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;

@SuppressLint("NewApi")
public class GifView extends View {
	
	/** 
     * 默认为1秒 
     */  
    private static final int DEFAULT_MOVIE_DURATION = 1000;  
  
    private int mMovieResourceId;  
  
    private Movie mMovie;  
  
    private long mMovieStart;  
  
    private int mCurrentAnimationTime = 0;  
  
    private float mLeft;  
  
    private float mTop;  
  
    private float mScale;  
  
    private int mMeasuredMovieWidth;  
  
    private int mMeasuredMovieHeight;  
  
    private boolean mVisible = true;  
  
    private volatile boolean mPaused = false;
    
	public GifView(Context context) {  
        this(context, null);  
    }  
  
    public GifView(Context context, AttributeSet attrs) {  
        this(context, attrs, R.styleable.CustomTheme_gifViewStyle);  
    }  
  
    public GifView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        setViewAttributes(context, attrs, defStyle);  
    }

	@SuppressLint("NewApi")
	private void setViewAttributes(Context context, AttributeSet attrs,
			int defStyle) {
		//如果版本>=11
		if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
			setLayerType(View.LAYER_TYPE_SOFTWARE, null);
		}
		// 从描述文件中读出gif的值,创建出Movie实例
		TypedArray array=context.obtainStyledAttributes
				(attrs, R.styleable.GifView, defStyle, R.style.AppTheme);
		mMovieResourceId = array.getResourceId(R.styleable.GifView_gif, -1);  
        mPaused = array.getBoolean(R.styleable.GifView_paused, false);
        array.recycle();
        if(mMovieResourceId!=-1){
        	mMovie=Movie.decodeStream(getResources().openRawResource(mMovieResourceId));
        }
	} 
	
	 /** 
     * 设置gif图资源 
     *  
     * @param movieResId 
     */
	public void setMovieResource(int movieResId) {  
        this.mMovieResourceId = movieResId;  
        mMovie = Movie.decodeStream(getResources().openRawResource(  
                mMovieResourceId));  
        requestLayout();  
    } 

	public void setMovie(Movie movie) {
		this.mMovie = movie;
		requestLayout();
	}

	public Movie getMovie() {
		return mMovie;
	}

	public void setMovieTime(int time) {
		mCurrentAnimationTime = time;
		invalidate();
	}

	/**
	 * 设置暂停
	 * 
	 * @param paused
	 */

	/*
	 * SystemClock.currentThreadTimeMillis(); // 在当前线程中已运行的时间
	 * SystemClock.elapsedRealtime(); // 从开机到现在的毫秒书(手机睡眠(sleep)的时间也包括在内)
	 * SystemClock.uptimeMillis(); // 从开机到现在的毫秒书(手机睡眠的时间不包括在内)
	 * SystemClock.sleep(100); //
	 * 类似Thread.sleep(100);但是该方法会忽略InterruptedException
	 * SystemClock.setCurrentTimeMillis(1000); //
	 * 设置时钟的时间,和System.setCurrentTimeMillis类似
	 */
	public void setPaused(boolean paused) {
		mPaused = paused;
		if (!paused) {
			mMovieStart = SystemClock.uptimeMillis() - mCurrentAnimationTime;
		}
		invalidate();
	}

	/**
	 * 判断gif图是否停止了
	 * 
	 * @return
	 */
	public boolean isPaused(){
		return mPaused;
	}
	
	//重新设置一下宽高
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		if(mMovie!=null){
			//获取movie的宽高
			int movieWidth=mMovie.width();
			int movieHeight=mMovie.height();
			int maximumWidth=MeasureSpec.getSize(widthMeasureSpec);
			float scaleW=(float)movieWidth/(float)maximumWidth;
			mScale=1f/scaleW;
			//进行伸缩
			mMeasuredMovieWidth=maximumWidth;
			mMeasuredMovieHeight=(int) (movieHeight*mScale);
			
			setMeasuredDimension(mMeasuredMovieWidth, mMeasuredMovieHeight);
		}else{
			setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
		}
	}
	
	//视图的绘制仅在Framework层分为三个阶段measure,layout,draw。
	//覆写onLayout的目的是为了指定视图的显示位置,
	//方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下,才能确定怎么摆放。
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		mLeft=(getWidth()-mMeasuredMovieWidth)/2f;
		mTop=(getHeight()-mMeasuredMovieHeight)/2f;
		mVisible=(getVisibility()==View.VISIBLE);
	}
	
	protected void onDraw(Canvas canvas) {
		if(mMovie!=null){
			if(!mPaused){
				updateAnimationTime();
				drawMovieFrame(canvas);
				invalidateView();
			}else{
				drawMovieFrame(canvas);
			}
		}
	}
	
	
	private void invalidateView() {
		if(mVisible){
			if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN){
				postInvalidateOnAnimation();
			}else{
				invalidate();
			}
		}
	}

	//更新动画时间
	@SuppressLint("NewApi")
	private void updateAnimationTime(){
		long now=SystemClock.uptimeMillis();
		//如果是第一帧,记录起始时间
		if(mMovieStart==0){
			mMovieStart=now;
		}
		//取出动画的时长
		int dur=mMovie.duration();
		if(dur==0){
			dur=DEFAULT_MOVIE_DURATION;
		}
		//算出需要显示第几帧
		mCurrentAnimationTime=(int) ((now-mMovieStart)%dur);
	}
	
	private void drawMovieFrame(Canvas canvas){
		//设置显示的帧,绘制即可
		mMovie.setTime(mCurrentAnimationTime);
		//用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
		canvas.save(Canvas.MATRIX_SAVE_FLAG);
		canvas.scale(mScale, mScale);
		mMovie.draw(canvas, mLeft/mScale, mTop/mScale);
		//用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
		canvas.restore();
		//注意:save和restore要配对使用(restore可以比save少,但不能多),
		//如果restore调用次数比save多,会引发Error。
	}
	
	@Override
	public void onScreenStateChanged(int screenState) {
		super.onScreenStateChanged(screenState);
		mVisible=(screenState==SCREEN_STATE_ON);
		invalidateView();
	}
	
	@Override
	protected void onVisibilityChanged(View changedView, int visibility) {
		super.onVisibilityChanged(changedView, visibility);
		mVisible=(visibility==VISIBLE);
		invalidateView();
	}
	
	@Override
	protected void onWindowVisibilityChanged(int visibility) {
		super.onWindowVisibilityChanged(visibility);
		mVisible=(visibility==VISIBLE);
		invalidateView();
	}
}
xml文件:

<LinearLayout  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="vertical"
    tools:context=".MainActivity" >

    <com.example.hello.GifView  
        android:id="@+id/gif1"  
        android:layout_width="match_parent"  
        android:layout_height="100dp"  
        android:layout_gravity="center_horizontal"  
        android:enabled="false" />  
  
    <com.example.hello.GifView  
        android:id="@+id/gif2"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:layout_gravity="center_horizontal"
        android:enabled="false" />

</LinearLayout >
activity中的代码:
gif1 = (GifView) findViewById(R.id.gif1);  
        // 设置背景gif图片资源  
		gif1.setMovieResource(R.raw.tu2);  
		gif2 = (GifView) findViewById(R.id.gif2);  
        gif2.setMovieResource(R.raw.tu1);  
        // 设置暂停  
        //gif2.setPaused(true);
自己下载两张gif格式的图片即可。

 
Movie其实管理着GIF动画中的多个帧,只需要通过 setTime() 一下就可以让它在draw()的时候绘出相应的那帧图像。通过当前时间与duration之间的换算关系,是很容易实现GIF动起来的效果。 

注意:与ImageView和其他View唯一的区别在于我加了一个gif属性。

在styles里添加这部分:

<declare-styleable name="GifView">
	    <attr name="gif" format="reference" />
	    <attr name="paused" format="boolean" />
	</declare-styleable>
	<declare-styleable name="CustomTheme">  
        <attr name="gifViewStyle" format="reference" />  
</declare-styleable> 


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值