gif动画在web开发中使用的非常的多,利用gif,许多动画不必再用程序编写,现在有非常多的App已经使用到了gif动画,可是android sdk并没有为我们提供gif这种View,所以我们只能自定义一个View,去实现gif效果.
android虽然没有为我们提供现成的GifView,但是为我们提供了Movie类,这个类就是用来实现GifView的关键类.它主要有两个最重要的方法,一个是根据动画播放时间设置当前要现显示的帧,二是将当前要显示的帧绘制到画布中.下面看一下效果图:
点击暂停按钮还可以暂停gif动画.
下面就看是如何实现的:
1.首先将需要用到的属性先自定义好:如下代码所示:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="gifCommon"> <attr name="gif_src" format="reference" /> <attr name="decode_stream" format="boolean" /> <attr name="default_animation_time" format="integer" /> </declare-styleable> </resources>
三个属性分别代表:gif资源,是否采用流编码,默认动画间隔时间.
2.自定义GifView代码.
package view; import java.io.ByteArrayOutputStream; import java.io.InputStream; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Movie; import android.util.AttributeSet; import android.view.View; import com.example.drawbaledemo.R; /** * @author rzq * */ public class GifView extends View { private Movie mMovie; /** * 动画开始时间 / private long mMovieStart; private boolean mPaused = false; /** * 当前帧动画时间 / private int mCurrentAnimationTime ; /** * 自定义的三个属性 / private boolean decode_STREAM; private int src_ID; private int default_time; public GifView(Context context) { super(context); init(context, null); } public GifView(Context context, AttributeSet set) { super(context, set); init(context, set); } private void init(Context context, AttributeSet set) { TypedArray a = context.obtainStyledAttributes(set, R.styleable.gifCommon); src_ID = a.getResourceId(R.styleable.gifCommon_gif_src, -1); decode_STREAM = a.getBoolean(R.styleable.gifCommon_decode_stream, true); default_time = a.getInteger( R.styleable.gifCommon_default_animation_time, 1000); a.recycle(); setFocusable(true); java.io.InputStream is; is = context.getResources().openRawResource(src_ID); if (decode_STREAM) { mMovie = Movie.decodeStream(is); // 根据文件流创建Movier绘制对象 } else { byte[] array = streamToBytes(is); mMovie = Movie.decodeByteArray(array, 0, array.length); } } @Override protected void onDraw(Canvas canvas) { if (mMovie != null) { if (!mPaused) { // 更新帧时间 updateAnimationTime(); drawMovieFrame(canvas); invalidate(); } else { // 暂停时,不更新帧时间,则只画当前帧 drawMovieFrame(canvas); } } } private void updateAnimationTime() { long now = android.os.SystemClock.uptimeMillis(); // 如果第一帧,记录起始时间 if (mMovieStart == 0) { mMovieStart = now; } // 取出动画的时长 int dur = mMovie.duration(); if (dur == 0) { dur = default_time; } // 算出需要显示第几帧 mCurrentAnimationTime = (int) ((now - mMovieStart) % dur); } private void drawMovieFrame(Canvas canvas) { // 设置要显示的帧,绘制即可 mMovie.setTime(mCurrentAnimationTime); canvas.save(Canvas.MATRIX_SAVE_FLAG); mMovie.draw(canvas, 0, 0); canvas.restore(); } /** * 设置暂停 * * @param paused */ public void setPaused(boolean paused) { this.mPaused = paused; if (!paused) { /** * 更新动画起点时间 */ mMovieStart = android.os.SystemClock.uptimeMillis() - mCurrentAnimationTime; } invalidate(); } /** * 判断gif图是否停止了 * * @return */ public boolean isPaused() { return this.mPaused; } /** * 重写此方法,使自定义View支持wrap_content */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { int desired = (int) (getPaddingLeft() + mMovie.width() + getPaddingRight()); width = Math.min(desired,widthSize); } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { int desired = (int) (getPaddingTop() + mMovie.height() + getPaddingBottom()); height = Math.min(desired,heightSize); } setMeasuredDimension(width, height); } /** * 将流转化为字节数组 * * @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(); } }
3.布局文件中使用GifView.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:gif="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#fed952" android:gravity="center" > <view.GifView android:id="@+id/gif_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ffffff" gif:decode_stream="true" gif:default_animation_time="1000" gif:gif_src="@drawable/animated_gif" /> <TextView android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/gif_view" android:text="暂停" /> </RelativeLayout>
与使用普通的View一样,将需要的资源传入即可.
时间: 2024-10-19 00:07:28