zoukankan      html  css  js  c++  java
  • android 拓展ImageView播放GIF动画

    原生Android控件ImageView并不能支持播放GiF格式的图片.如果将一张GIF的图片放入ImageView中,它只会显示图片的第一帧,不会产生任何动画效果.
    Android中播放GIF动画实现方法还是用多种的,最常用的就是使用   Frame动画, 但局限性较多,所以下面用一种拓展的ImageView实现效果.

        
    1.要用到自定义控件,就要使用自定义控件的属性,因此需要在values下新建一个attrs.xml,可以为这个文件中添加任何需要自定义的属性.
    这里只需要一个auto_play,标志是否自动播放.
    <?xml version="1.0" encoding="utf-8"?>  
    <resources>  
      
        <declare-styleable name="PowerImageView">  
            <attr name="auto_play" format="boolean"></attr>  
        </declare-styleable>  
      
    </resources>   
    2.下面开始写最重要的MyImageView继承自ImageView.
    public class MyImageView extends ImageView implements OnClickListener {
        
        private Movie mMovie;   //播放GIF动画的关键类
        
        private Bitmap mStartBitmap;   //播放按钮
        
        private long mMovieStart;  //动画开始的时间
        private int mImageWidth;  //GIF图片的宽度
        
        private int mImageHeight;  //GIF图片的高度
        
        private boolean isPlaying;   //标志是否正在播放
        
        private boolean isAutoPlay;  //是否自动播放
        
        
        public MyImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.PowerImageView);
            int resourceId=getResourceId(a, context, attrs);
            if(resourceId!=0){
                //获取该资源的流
                InputStream is=getResources().openRawResource(resourceId);
                //使用Movie对流进行解码
                mMovie=Movie.decodeStream(is);
                if(mMovie!=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){
                        mStartBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
                        setOnClickListener(this);
                    }
                }
            }
            
        
        }
        
        
        
        //通过Java反射,获取到src指定图片资源所对应的id。
        private int getResourceId(TypedArray a, Context context,AttributeSet attrs){
            try {
                Field field =TypedArray.class.getDeclaredField("mValue");
                field.setAccessible(true);
                TypedValue typeValueObject=(TypedValue) field.get(a);
                return typeValueObject.resourceId;
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }
                return 0;
        }
        
        
        @Override
        public void onClick(View v) {
            if(v.getId()==getId()){
                isPlaying=true;
                invalidate();
            }
        }
        
        @Override
        protected void onDraw(Canvas canvas) {
            if(mMovie==null){
                super.onDraw(canvas);
            }
            else{
                if(isAutoPlay){
                    playMovie(canvas);
                    invalidate();
                }
                else{
                    if(isPlaying){
                        if(playMovie(canvas)){
                            isPlaying=false;
                        }
                        invalidate();
                    }
                    else{
                        mMovie.setTime(0);
                        mMovie.draw(canvas, 0, 0);
                        int offsetW=(mImageWidth-mStartBitmap.getWidth())/2;
                        int offsetH=(mImageHeight=mStartBitmap.getHeight())/2;
                        canvas.drawBitmap(mStartBitmap, offsetW, offsetH,null);
                    }
                }
            }
            
        }
        
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if(mMovie!=null){
                setMeasuredDimension(mImageWidthmImageHeight);
            }
        }
        
        //开始播放GIF动画   当播放结束返回true.
        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;
        }
        
    }  
    上面代码中,playMovie是播放动画的关键方法.
    3.activity_main.xml
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:attr="http://schemas.android.com/apk/res/com.example.powerimageviewdemo" 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
        <com.example.powerimageviewdemo.MyImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/vv"
            attr:auto_play="false"
            />
    </RelativeLayout> 
    使用src属性可以指定任意一张图片,如果是GIF图片,则会进行播放,如果auto_play设置的是false,则不会自动播放.
    有些手机启用了硬件加速功能后导致GIF动画播放不了.需要在AndroidManifest.xml 进行配置.

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     package="com.example.mydemo"  
    4.     android:versionCode="1"  
    5.     android:versionName="1.0" >  
    6.   
    7.     <uses-sdk  
    8.         android:minSdkVersion="14"  
    9.         android:targetSdkVersion="17" />  
    10.   
    11.     <application  
    12.         android:allowBackup="true"  
    13.         android:icon="@drawable/ic_launcher"  
    14.         android:label="@string/app_name"  
    15.         android:theme="@style/AppTheme"   
    16.         android:hardwareAccelerated="false"  
    17.         >  
    18.         <activity  
    19.             android:name="com.example.mydemo.MainActivity"  
    20.             android:label="@string/app_name" >  
    21.             <intent-filter>  
    22.                 <action android:name="android.intent.action.MAIN" />  
    23.                 <category android:name="android.intent.category.LAUNCHER" />  
    24.             </intent-filter>  
    25.         </activity>  
    26.     </application>  
    27.   
    28. </manifest> 
       

     

     





    qq3061280@163.com
  • 相关阅读:
    vue组件间传值
    Kth MIN-MAX 反演
    BZOJ4671 异或图(容斥+线性基)
    hihoCoder #1646 : Rikka with String II(容斥原理)
    字符串小结
    LOJ# 572. 「LibreOJ Round #11」Misaka Network 与求和(min25筛,杜教筛,莫比乌斯反演)
    SPOJ divcntk(min25筛)
    LA3490 Generator(KMP + 高斯消元)
    ExKMP(Z Algorithm) 讲解
    BZOJ 2728: [HNOI2012]与非(位运算)
  • 原文地址:https://www.cnblogs.com/aibuli/p/93a21558fc6bcf309796a658601bd381.html
Copyright © 2011-2022 走看看