• 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功能

    源码下载,请点击这里

  • 相关阅读:
    “There appears to be trouble with your network connection. Retrying”
    Nignx 处理异常操作流程
    "...do not match previously installed version; ignoring!"
    文档对象模型(DOM)
    Parsing error: Expression expected.
    让人抓狂的缩进冲突(eslint)
    C#中属性PropertyInfo的使用
    C#调用WebService服务(动态调用)
    pdf转word工具
    PASS系统应用技术手册
  • 原文地址:https://www.cnblogs.com/qlky/p/5698507.html
Copyright © 2020-2023  润新知