Android的开发框架为我们的开发提供了不少很棒的控件,我们在开发的时候不需要太多的编码就能轻松方便的使用这些控件,不过有些时候这些系统自带的控件并不能够完全满足我们的需求。这时就需要我们发挥自己的想象力来实现我们特定需求的控件。

       今天为大家带来一款可以展示Gif图片的控件,实现播放Gif图片的方法不止这一种,你也可以选择其他的方式来实现(比如自己写一个库利用JNI调用或者直接用WebView来做展示),不过那就比较麻烦了,Android提供了可以展示类似这样的文件的方法,利用这些方法可以降低实现难度而且效果不会变差。

       展示图片的过程实际上就是我们把图片解码到屏幕上的过程。Android为我们提供了一个叫做Movie的类可以帮我们实现解码。这个控件不但可以用作展示Gif图片也可以当做普通的ImageView控件来使用。下面我们通过代码来详细解释如何实现的

       首先看一下Demo的目录结构

                                                    

android 打开图库 打开视频_控件

       目录结构非常简单,主要用到的类就只有GIFView一个。下面贴出其中的代码为大家详细解释

      

package com.example.gifview;


import java.io.InputStream;
import java.lang.reflect.Field;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Movie;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ImageView;


public class GifView extends ImageView {

	/**
	 * Movie对象用来解析gif图片
	 */
	private Movie gifMovie;

	/**
	 * 开始时间,用来和当前时间比较,得出什么时间播放gif
	 */
	private long mMovieStart;

	/**
	 * gif图片的宽
	 */
	private int gifImageWidth;

	/**
	 * gif图片的高
	 */
	private int gifImageHeight;

	
	/**
	 * 访问attrs
	 */
	private AttributeSet attrs;

	/**
	 * 复写GifView的构造方法
	 * 
	 * @param context
	 */
	public GifView(Context context) {
		super(context);
		
	}

	/**
	 * 复写的GifView的构造方法
	 * 
	 * @param context
	 * @param attrs
	 */
	public GifView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.attrs = attrs;
		loadGifImage();
	}
	
	private void loadGifImage(){
		AttributeSet attrs = getContext().getResources().getXml(R.id.gifView);
		
		//生成一个TypedArray对象
		TypedArray array = getContext().obtainStyledAttributes(attrs,
				R.styleable.weatherView);
		
		//得到资源id
		int resourceId = getResourceId(array);
		
//检查资源id
if(resourceId == -1){
	System.out.println("没有获取到图片Id,请检查是否在xml文件里设置了src属性");
}

		// 以流的方式得到gif文件
		InputStream is = getResources().openRawResource(resourceId);

		// 用Movie的decodeStream方法解码文件
		gifMovie = Movie.decodeStream(is);
		if (gifMovie != null) {
			Bitmap bitmap = BitmapFactory.decodeStream(is);
			gifImageWidth = bitmap.getWidth();
			gifImageHeight = bitmap.getHeight();
			bitmap.recycle();
		}
		
		
	}

	/**
	 *  复写onDraw方法用于绘制View
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		if (gifMovie == null) {
			// 如果Movie为空说明不是一个gif图像,不是则调用父类方法,此时该控件等同于ImageView
			super.onDraw(canvas);
		} else {
			// 如果Movie不为空则说明是一个gif图像则展示gif图像
			showGifImage(canvas);
			// 刷新
			invalidate();
		}
	}

	/**
	 *  复写onMeasure方法,用来设置Gif宽高
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (gifMovie != null) {
			// 设置尺寸
			setMeasuredDimension(gifImageWidth, gifImageHeight);
		}
	}

	// 封装的展示gif的方法
	private boolean showGifImage(Canvas canvas) {
		//得到系统时间
		long now = SystemClock.uptimeMillis();
		if (mMovieStart == 0) {
			// 把开始时间设置为当前时间
			mMovieStart = now;
		}
		int duration = gifMovie.duration();
		if (duration == 0) {
			// 如果没有持续时间就设置为100
			duration = 100;
		}

		// 设置间隔时间
		int relTime = (int) ((now - mMovieStart) % duration);
		gifMovie.setTime(relTime);
		
		//在指定的位置进行绘制,这里是左上角
		gifMovie.draw(canvas, 0, 0);
		if ((now - mMovieStart) >= duration) {
			mMovieStart = 0;
			return true;
		}
		return false;
	}

	/**
	 * 解析xml文件里的src传来的参数,需要传入一个TypeArray,Context,和参数数组AttributeSet
	 * 
	 * @param array
	 * @param context
	 * @param attrs
	 * @return
	 */
	private int getResourceId(TypedArray array
			) {
		try {

			// 得到一个TypedArray里的域
			Field field = TypedArray.class.getDeclaredField("mValue");

			// 设置可访问性为true
			field.setAccessible(true);

			// 从类中取得域值
			TypedValue typeValueObject = (TypedValue) field.get(array);
			
			return typeValueObject.resourceId;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			array.recycle();
		}
		return -1;
	}
	
}


       我们先声明一个Movie的对象,准备用来解析Gif图片,然后我们需要一个变量来记录开始播放的时间,用两个整形变量来记录需要播放的Gif图片的宽高,最后我们实现播放Gif的基类是ImageView,相当于ImageView+Movie来实现的这个功能。需要顺便一提的是,这里用到一点关于Java反射的内容,为的是拿到配置文件里的Gif图片ID。代码如下:

      

//生成一个TypedArray对象
		TypedArray array = getContext().obtainStyledAttributes(attrs,
				R.styleable.weatherView);
		
		//得到资源id
		int resourceId = getResourceId(array);

        首先用loadImage()来载入Gif图片,载入的时候需要得到图片的宽高。

        自己实现控件除了继承之外实现onMeasure和onDraw方法也是必要的。在onMeasure里可以设置尺寸,同时可以判断Movie对象是否为空,来决定这次展示是作为普通图片还是Gif图片来展示。

         在showGifImage方法里就是实现展示Gif图片的关键部分,这里需要对Movie的duration属性进行设置。用来控制播放周期。

 

 

       之后的过程就比较容易了,像普通的控件一样来使用就可以了。下面是布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

	<com.example.gifview.GifView 
	    android:id="@+id/gifView"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content"
	    android:src="@drawable/weather_gif"/>
	
	<TextView 
	    android:id="@+id/textView1"
	    android:layout_below="@id/gifView"
	    android:layout_width="wrap_content"
	    android:layout_height="wrap_content"
	    android:text="演示gif控件"/>
</RelativeLayout>

        这里<com.example.gifview.GifView>就是我们需要的Gif控件。

 

        然后是在Activity里设置布局文件

 



package com.example.gifview;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

 

顺便需要提一下,在使用这个空间时可能需要设置硬件加速为false

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gifview"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:hardwareAccelerated="false" >
        <activity
            android:name="com.example.gifview.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

android 打开图库 打开视频_android 打开图库 打开视频_02