• Android应用系列:完美运行GIF格式的ImageView(附源码)


    前言

      我们都知道ImageView是不能完美加载Gif格式的图片,如果我们在ImageView中src指定的资源是gif格式的话,我们将会惊喜的发觉画面永远停留在第一帧,也就是不会有动画效果。当然,经过略加改造,我们是可以让gif在ImageView上完美加载的。

    正文

      Android给我们提供了一个Movie类,可以让我们实现加载gif格式资源的目标。我们需要导入android.graphics.Movie这个包,当然这个也是Android自带的。所以我们的主要方法是继承一个ImageView的子类,通过改写其中的onDraw方法加载gif资源。话也不多说了,通过代码大家看的更明白,文末附带源码哦。

    PS:看懂本文需要了解自定义View的相关知识。

    attrs资源文件:

    <resources>
        <declare-styleable name="GifView"> 
            <attr name="isgifimage" format="boolean"/>
        </declare-styleable>
    </resources>

    我在这里面设置了一个自定义属性 isgifimage,目的是让用户自行设置控件显示是否是gif格式资源,因为非gif格式资源用Movie加载也是可以显示图像,但是效率就肯定没有原生控件加载模式好,当然,默认isgifimage为true,也就是默认为gif格式的资源。

    自定义的GifView的构造函数(GifView类继承ImageView)

    public GifView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取自定义属性isgifimage
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GifView);
        isGifImage = array.getBoolean(R.styleable.GifView_isgifimage, true);
        array.recycle();//获取自定义属性完毕后需要recycle,不然会对下次获取造成影响
        //获取ImageView的默认src属性
        image = attrs.getAttributeResourceValue( "http://schemas.android.com/apk/res/android", "src", 0); 
        
        movie = Movie.decodeStream(getResources().openRawResource(image));
    }

    在GifView的构造方法中,我们主要是对GifView的自定义属性进行获取。可以通过context.obtainStyledAttributes(attrs, R.styleable.GifView)返回一个TypedArray对象,然后从该对象分别获取自定义属性,在这里需要强调一点的时R.styleable.GifView_isgifimage,红色的时attrs资源文件的名字,而蓝色则是其对应的属性名字(见attrs资源文件),中间以下划线分隔。

    在我们获取完自定义属性后必须recycle(),不然会对下次该控件获取自定义属性造成影响,因为TypedArray对象是公共资源。

    然后我们在通过attrs.getAttributeResourceValue( "http://schemas.android.com/apk/res/android", "src", 0)来获取ImageView的原生src属性,并将其传入movie实例中。

    自定义GifView的onDraw方法

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);//执行父类onDraw方法,绘制非gif的资源
        if(isGifImage){//若为gif文件,执行DrawGifImage(),默认执行
            DrawGifImage(canvas);
        }
    }
    
    private void DrawGifImage(Canvas canvas) {
        //获取系统当前时间
        long nowTime = android.os.SystemClock.currentThreadTimeMillis();
        if(movieStart == 0){
            //若为第一次加载,开始时间置为nowTime
            movieStart = nowTime;
        }
        if(movie != null){//容错处理
            int duration = movie.duration();//获取gif持续时间
            //如果gif持续时间小于100,可认为非gif资源,跳出处理
            if(duration > 100){
                //获取gif当前帧的显示所在时间点
                int relTime = (int) ((nowTime - movieStart) % duration);
                movie.setTime(relTime);
                //渲染gif图像
                movie.draw(canvas, 0, 0);
                invalidate();
            }
        }
    }

    在这个方法中,我们先对isGifImage是否为true进行判断,如果开发者指定其为false则直接调用super.onDraw(canvas)绘制即可,而不必调用DrawGifImage()来降低效率,毕竟不断的invalidate()对性能效率还是蛮大的。

    如果要绘制gif资源,我们会根据系统的时间来推断出当前时间点时gif资源所应该显示的时间帧,相信大家看代码更容易看懂,注释也够详细的了,就不多讲解了。

    调用资源的xml文件:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:gifview="http://schemas.android.com/apk/res/com.net168.testgifview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <com.net168.gifview.GifView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/image"
            gifview:isgifimage="true"
            />
    </LinearLayout>

    需要注意的一点就是 xmlns:gifview="http://schemas.android.com/apk/res/com.net168.testgifview",其中红色部分GifView.java这个类所在的包名。

    下面附上源码(GifView.rar为lib工程,TestGIfView.rar为调试工程):MyGif.rar

    作者:enjoy风铃
    出处:http://www.cnblogs.com/net168/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则下次不给你转载了

  • 相关阅读:
    nodejs基础文档
    vue_项目心得
    常见的布局方式
    前端 + node + ajax mysql 实现数据的提交
    node创建包
    node学习站
    血一般的教训,请慎用Insert Into Select
    继杭州购房宝典后,Github上的这个程序员买房实用指南火了!
    MySQL入门到精通:MySQL 删除数据库
    C语言中的 int** 是什么?这要从int* 和int 说起...
  • 原文地址:https://www.cnblogs.com/net168/p/4204797.html
Copyright © 2020-2023  润新知