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