Android的原生控件并不支持播放GIF格式的图片。我们都知道,在Android中如果想要显示一张图片,可以借助ImageView来完成,但是如果将一张GIF图片设置到Ima
Android的原生控件并不支持播放GIF格式的图片。我们都知道,在Android中如果想要显示一张图片,可以借助ImageView来完成,但是如果将一张GIF图片设置到ImageView里,它只会显示这张图片的第一帧,不会产生任何的动画效果。今天我们来编写一个自定义的增强型ImageView(继承ImageView),可以播放GIF格式的图片,暂且叫做GifImageView吧。
1.自定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="GifImageView">
<attr name="auto_play" fORMat="boolean"></attr>
</declare-styleable>
</resources>
2.自定义View中获取属性值
private Movie mMovie;//播放动画需要用到的,系统类
private int mImageWidth;//动画的imageview的宽度
private int mImageHeight;//动画imageview的高度
private long mMovieStart = 0;// 播放开始
private boolean isAutoPlay;//是否自动播放
private Bitmap mStartPlay;//开始按钮
private boolean isPlaying=false;//记录是否正在播放
private float mScale;//图片的缩放比
private int mMeasuredGifWidth;//缩放后图片宽
private int mMeasuredGifHeight;//缩放后图片高
...
private void init(Context context, AttributeSet attrs) {
TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.GifImageView);
// 通过反射拿布局中src的资源id,所以gif文件需要放在布局的src中
int resourceId = getResourceId(attributes, context, attrs);
if (resourceId != 0) {
// 说明是gif动画
// 1.将resourcesId变成流
// 2.用Move来decode解析流
// 3.获得bitmap的长宽
InputStream is = getResources().openRawResource(resourceId);
mMovie = Movie.decodeStream(is);
if (mMovie != null) {
Bitmap bitmap = BitmapFactory.decodeStream(is);
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
// 用完释放
bitmap.recycle();
// 获得是否允许自动播放,如果不允许自动播放,则初始化播放按钮
isAutoPlay = attributes.getBoolean(R.styleable.GifImageView_auto_play, false);
if (!isAutoPlay) {
mStartPlay = BitmapFactory.decodeResource(getResources(),R.drawable.start_play);
setOnClickListener(this);
}
}
}
//回收资源
attributes.recycle();
}
private int getResourceId(TypedArray attributes, Context context, AttributeSet attrs) {
try {
Field filed = TypedArray.class.getDeclaredField("mValue");
filed.setAccessible(true);
TypedValue typeValue = (TypedValue) filed.get(attributes);
return typeValue.resourceId;
} catch (Exception e) {
e.printStackTrace();
}
}
return 0;
}
3.重写onMesure()
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mMovie != null) {
float scaleW = 1f;
int measureModeWidth = MeasureSpec.getMode(widthMeasureSpec);
if (measureModeWidth != MeasureSpec.UNSPECIFIED) {
int maximumWidth = MeasureSpec.getSize(widthMeasureSpec);
scaleW = (float) mImageWidth / (float) maximumWidth;
}
float scaleH = 1f;
int measureModeHeight = MeasureSpec.getMode(heightMeasureSpec);
if (measureModeHeight != MeasureSpec.UNSPECIFIED) {
int maximumHeight = MeasureSpec.getSize(heightMeasureSpec);
scaleH = (float) mImageHeight / (float) maximumHeight;
}
mScale = 1f / Math.max(scaleH, scaleW);
mMeasuredGifWidth = (int) (mImageWidth * mScale);
mMeasuredGifHeight = (int) (mImageHeight * mScale);
setMeasuredDimension(mMeasuredGifWidth, mMeasuredGifHeight);
}
}
4.重写onDraw()
@Override
protected void onDraw(canvas canvas) {
if (mMovie == null) {
// mMovie等于null,说明是张普通的图片,则直接调用父类的onDraw()方法
super.onDraw(canvas);
} else {
// mMovie不等于null,说明是张GIF图片
if (isAutoPlay) {
// 如果允许自动播放,就播放
playMovie(canvas);
invalidate();
} else {
// 不允许自动播放的话
// 1.判断是否正在播放
// 2.获得第一帧的图像
// 3.然后添加播放按钮
if (isPlaying) {
// 如果正在播放就playmoive继续播放
if (playMovie(canvas)) {
isPlaying = false;
}
invalidate();
} else {
// 第一帧
mMovie.setTime(0);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale);
mMovie.draw(canvas, 0, 0);// 画
canvas.restore();
// 绘制开始按钮
int offsetW = (mMeasuredGifWidth - mStartPlay.getWidth()) / 2;
int offsetH = (mMeasuredGifHeight - mStartPlay.getHeight()) / 2;
canvas.drawBitmap(mStartPlay, offsetW, offsetH, null);
}
}
}
}
private boolean playMovie(Canvas canvas) {
// 1.获取播放的时间
// 2.如果开始start=0,则认为是开始
// 3.记录播放的时间
// 4.设置进度
// 5.画动画
// 6.如果时间大于了播放的时间,则证明结束
long now = SystemClock.uptimeMillis();
if (mMovieStart == 0) {
mMovieStart = now;
}
int duration = mMovie.duration();
if (duration == 0) {
duration = 1000;
}
//记录gif播放了多少时间
int relTime = (int) ((now - mMovieStart) % duration);
mMovie.setTime(relTime);// 设置时间
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale);
mMovie.draw(canvas, 0, 0);// 画
canvas.restore();
if ((now - mMovieStart) >= duration) {
// 结束
mMovieStart = 0;
return true;
}
return false;
}
5.添加点击事件
@Override
public void onClick(View v) {
if(v.getId()==getId()){
isPlaying=true;
invalidate();
}
}
还有一点需要注意,有些4.0以上系统的手机启动了硬件加速功能之后会导致GIF动画播放不出来,因此我们需要在AndroidManifest.xml中去禁用硬件加速功能,可以通过指定android:hardwareAccelerated=false来完成。
--------------------------------------------------------------------------------
现在我们来看看运行后效果如何吧,
布局文件:
<LinearLayout 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.hx.gifimageview"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.hx.gifimageview.GifImageView
android:layout_width="150dip"
android:layout_height="150dip"
android:layout_margin="10dp"
android:src="@drawable/shulan"
attr:auto_play="false" />
<com.hx.gifimageview.GifImageView
android:layout_width="150dip"
android:layout_height="150dip"
android:layout_margin="10dp"
android:src="@drawable/shulan"
attr:auto_play="true" />
<com.hx.gifimageview.GifImageView
android:layout_width="150dip"
android:layout_height="150dip"
android:layout_margin="10dp"
android:src="@drawable/jingtai"
attr:auto_play="true" />
</LinearLayout>
图一的auto_play属性为false,会显示第一帧和一个播放按钮,点击后Gif图片会自动运行。
图二的auto_play属性为true,会自动循环播放Gif。
图三我们给的资源是静态图片,因为自定义View继承ImageView,所以具备ImageView所有特性,因此也能显示静态图片。
源码下载:http://xiazai.jb51.net/201609/yuanma/GifImageView(jb51.net).rar
您可能感兴趣的文章:Android自定义控件之圆形、圆角ImageViewAndroid实现ImageView阴影和图层效果Android实现ImageView图片缩放和拖动Android实现圆角矩形和圆形ImageView的方式Android使用CircleImageView实现圆形头像的方法Android实现ImageView图片双击放大及缩小Android布局自定义Shap圆形ImageView可以单独设置背景与图片Android长按imageview把图片保存到本地的实例代码
--结束END--
本文标题: Android实现可播放GIF动画的ImageView
本文链接: https://lsjlt.com/news/23987.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0