Android-自定义View实现ImageView播放gif

http://blog.csdn.net/guolin_blog/article/details/11100315

总体思路是这样的

PowerImageView类继承ImageView类

给PowerImageView类添加自定义属性auto_play

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <com.example.customview.CounterView  
        android:layout_width="100dp"  
        android:layout_height="100dp"  
        android:layout_centerInParent="true" />  
  
</RelativeLayout> 

构造函数中,初始化:

得到资源id,通过id获取流,判断是不是gif图片

如果是gif图片,需要得到:auto_play,图片长度,图片宽度这三个属性

public PowerImageView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PowerImageView);  
        int resourceId = getResourceId(a, context, attrs);  
        if (resourceId != 0) {  
            // 当资源id不等于0时,就去获取该资源的流  
            InputStream is = getResources().openRawResource(resourceId);  
            // 使用Movie类对流进行解码  
            mMovie = Movie.decodeStream(is);  
            if (mMovie != null) {  
                // 如果返回值不等于null,就说明这是一个GIF图片,下面获取是否自动播放的属性  
                isAutoPlay = a.getBoolean(R.styleable.PowerImageView_auto_play, false);  
                Bitmap bitmap = BitmapFactory.decodeStream(is);  
                mImageWidth = bitmap.getWidth();  
                mImageHeight = bitmap.getHeight();  
                bitmap.recycle();  
                if (!isAutoPlay) {  
                    // 当不允许自动播放的时候,得到开始播放按钮的图片,并注册点击事件  
                    mStartButton = BitmapFactory.decodeResource(getResources(),  
                            R.drawable.start_play);  
                    setOnClickListener(this);  
                }  
            }  
        }  
    }

得到资源id的方法有两个:

1.反射

/** 
     * 通过Java反射,获取到src指定图片资源所对应的id。 
     *  
     * @param a 
     * @param context 
     * @param attrs 
     * @return 返回布局文件中指定图片资源所对应的id,没有指定任何图片资源就返回0。 
     */  
    private int getResourceId(TypedArray a, Context context, AttributeSet attrs) {  
        try {  
            Field field = TypedArray.class.getDeclaredField("mValue");  
            field.setAccessible(true);  
            TypedValue typedValueObject = (TypedValue) field.get(a);  
            return typedValueObject.resourceId;  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            if (a != null) {  
                a.recycle();  
            }  
        }  
        return 0;  
    }

这个方法可以得到的不仅仅是自定义的属性,给ImageView设置的所有属性都可以一起得到。

2.通过attr的方法

for (int i = 0; i < attrs.getAttributeCount(); i++) 
{
  if(attrs.getAttributeName(i).equals("src"))
  {
    System.out.println(attrs.getAttributeResourceValue(i, 0)+"=========");
    return attrs.getAttributeResourceValue(i, 0);
  }
}

播放gif的方法:

保存起始时间,判断现在时间-起始时间是否大于动画长度,大于则停

下面我们来看看playMovie()方法中是怎样播放GIF图片的吧。可以看到,首先会对动画开始的时间做下记录,然后对动画持续的时间做下记录,接着使用当前的时间减去动画开始的时间,得到的时间就是此时PowerImageView应该显示的那一帧,然后借助Movie对象将这一帧绘制到屏幕上即可。之后每次调用playMovie()方法都会绘制一帧图片,连贯起来也就形成了GIF动画。注意,这个方法是有返回值的,如果当前时间减去动画开始时间大于了动画持续时间,那就说明动画播放完成了,返回true,否则返回false。

/** 
     * 开始播放GIF动画,播放完成返回true,未完成返回false。 
     *  
     * @param canvas 
     * @return 播放完成返回true,未完成返回false。 
     */  
    private boolean playMovie(Canvas canvas) {  
        long now = SystemClock.uptimeMillis();  
        if (mMovieStart == 0) {  
            mMovieStart = now;  
        }  
        int duration = mMovie.duration();  
        if (duration == 0) {  
            duration = 1000;  
        }  
        int relTime = (int) ((now - mMovieStart) % duration);  
        mMovie.setTime(relTime);  
        mMovie.draw(canvas, 0, 0);  
        if ((now - mMovieStart) >= duration) {  
            mMovieStart = 0;  
            return true;  
        }  
        return false;  
    }

绘制gif:

onMeasure规定图片大小,gif则用setMeasuredDimension给定大小

@Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
        if (mMovie != null) {  
            // 如果是GIF图片则重写设定PowerImageView的大小  
            setMeasuredDimension(mImageWidth, mImageHeight);  
        }  
    }

onDraw绘制图片,非gir则用默认

起始时绘制开始按钮

isplaying时继续调用play_movie,再invalidate()

@Override  
    protected void onDraw(Canvas canvas) {  
        if (mMovie == null) {  
            // mMovie等于null,说明是张普通的图片,则直接调用父类的onDraw()方法  
            super.onDraw(canvas);  
        } else {  
            // mMovie不等于null,说明是张GIF图片  
            if (isAutoPlay) {  
                // 如果允许自动播放,就调用playMovie()方法播放GIF动画  
                playMovie(canvas);  
                invalidate();  
            } else {  
                // 不允许自动播放时,判断当前图片是否正在播放  
                if (isPlaying) {  
                    // 正在播放就继续调用playMovie()方法,一直到动画播放结束为止  
                    if (playMovie(canvas)) {  
                        isPlaying = false;  
                    }  
                    invalidate();  
                } else {  
                    // 还没开始播放就只绘制GIF图片的第一帧,并绘制一个开始按钮  
                    mMovie.setTime(0);  
                    mMovie.draw(canvas, 0, 0);  
                    int offsetW = (mImageWidth - mStartButton.getWidth()) / 2;  
                    int offsetH = (mImageHeight - mStartButton.getHeight()) / 2;  
                    canvas.drawBitmap(mStartButton, offsetW, offsetH, null);  
                }  
            }  
        }  
    }

然后我们还可以通过修改activity_main.xml中的代码,给它加上允许自动播放的属性,代码如下所示:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    xmlns:attr="http://schemas.android.com/apk/res/com.example.powerimageviewtest"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <com.example.powerimageviewtest.PowerImageView  
        android:id="@+id/image_view"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true"  
        android:src="@drawable/anim"  
        attr:auto_play="true"  
        />  
  
</RelativeLayout>  

注意:

这里不能对gif的大小进行设置,gif多大,显示出来就是多大。这里主要是演示自定义view,并不是专门实现gif功能

源码下载,请点击这里

原文地址:https://www.cnblogs.com/qlky/p/5698507.html