一、需求

Android本身没有提供直接显示gif动画的相关控件,因此需要自定义GifImageView类来实现gif的播放,主要是使用的Movie类来解决的。

二、自定义GifImageView

public class GifImageView extends AppCompatImageView {
private static final String TAG = "ImageView";
private static final int DEFAULT_MOVIE_DURATION = 2000;
private Movie mMovie;
private long mMovieStart;
private int mCurrentAnimationTime; /**
* Scaling factor to fit the animation within view bounds.
*/
private float mScale = 1;
private boolean mVisible = true; public GifImageView(Context context) {
this(context, null);
} public GifImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public GifImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setViewAttributes();
} @SuppressLint("NewApi")
public void setViewAttributes() {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mMovie != null) {
updateAnimationTime();
drawMovieFrame(canvas);
invalidateView();
}
} /**
* Draw current GIF frame
*/
private void drawMovieFrame(Canvas canvas) {
mMovie.setTime(mCurrentAnimationTime);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScale, mScale);
mMovie.draw(canvas, 0, 0);
canvas.restore();
} /**
* Calculate current animation time
*/
private void updateAnimationTime() {
long now = android.os.SystemClock.uptimeMillis(); if (mMovieStart == 0) {
mMovieStart = now;
} int dur = mMovie.duration(); if (dur == 0) {
dur = DEFAULT_MOVIE_DURATION;
} mCurrentAnimationTime = (int) ((now - mMovieStart) % dur);
} /**
* Invalidates view only if it is visible.
*/
@SuppressLint("NewApi")
private void invalidateView() {
if (mVisible) {
postInvalidateOnAnimation();
}
} @SuppressLint("NewApi")
@Override
public void onScreenStateChanged(int screenState) {
super.onScreenStateChanged(screenState);
mVisible = screenState == SCREEN_STATE_ON;
invalidateView();
} @SuppressLint("NewApi")
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
} @Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mVisible = visibility == View.VISIBLE;
invalidateView();
} public void setMovieResource(int movieResId) {
mMovie = Movie.decodeStream(getResources().openRawResource(movieResId));
requestLayout();
} @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed && mMovie != null) {
float scaleW = (float) getWidth() / mMovie.width();
float scaleH = (float) getHeight() / mMovie.height();
mScale = Math.min(scaleH, scaleW);
}
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mMovie != null) {
int mMeasureWidth;
int mMeasureHeight;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST) {
Log.e(TAG, "---moviewidth before" + mMovie.width());
int movieWidth = mMovie.width();
mMeasureWidth = Math.min(movieWidth, widthSize);
Log.e(TAG, "---moviewidth after" + mMovie.width());
} else {
mMeasureWidth = widthSize;
}
if (heightMode == MeasureSpec.AT_MOST) {
Log.e(TAG, "---height " + mMovie.height());
int movieHieght = mMovie.height();
mMeasureHeight = Math.min(movieHieght, heightSize); } else {
mMeasureHeight = heightSize;
}
Log.e(TAG, "--wi : " + mMeasureWidth + " h : " + mMeasureHeight);
setMeasuredDimension(mMeasureWidth, mMeasureHeight);
}
}
}

三、layout中添加控件

<com.pax.view.GifImageView
android:id="@+id/gif"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/space_horizontal"
android:layout_gravity="center"
android:visibility="invisible"/>

四、activity中实现

直接调用set方法,将gif资源传给gifview即可。

例如:

@Bind(R.id.gif)
GifImageView gif;

gif.setMovieResource(R.drawable.gif_searching);

Android中实现gif动画的更多相关文章

  1. android中设置Animation 动画效果

    在 Android 中, Animation 动画效果的实现可以通过两种方式进行实现,一种是 tweened animation 渐变动画,另一种是 frame by frame animation ...

  2. Android(java)学习笔记199:Android中补间动画(Tween Animation)

    本文主要简单介绍补间动画使用代码实现, 关于使用xml实现补间动画,可以参看:自定义控件三部曲之动画篇(一)——alpha.scale.translate.rotate.set的xml属性及用法 1. ...

  3. 在Android中显示GIF动画

    gif图动画在android中还是比较常用的,比如像新浪微博中,有很多gif图片,而且展示非常好,所以我也想弄一个.经过我多方的搜索资料和整理,终于弄出来了,其实github上有很多开源的gif的展示 ...

  4. 【转】[置顶] 在Android中显示GIF动画

    gif图动画在Android中还是比较常用的,比如像新浪微博中,有很多gif图片,而且展示非常好,所以我也想弄一个.经过我多方的搜索资料和整理,终于弄出来了,其实github上有很多开源的gif的展示 ...

  5. Android(java)学习笔记142:Android中补间动画(Tween Animation)

    本文主要简单介绍补间动画使用代码实现, 关于使用xml实现补间动画, 可以参看:自定义控件三部曲之动画篇(一)——alpha.scale.translate.rotate.set的xml属性及用法 1 ...

  6. Android中的帧动画与补间动画的使用

    前言 在日常开发中,我们有时候须要一些好看的动画效果,这时能够充分利用Android提供的这几种动画来实现. Android提供了3种类型的动画: 补间动画:补间动画能够应用于View,让你能够定义一 ...

  7. Android中的布局动画

    简介 布局动画是给布局的动画,会影响到布局中子对象 使用方法 给布局添加动画效果: 先找到要设置的layout的id,然后创建布局动画,创建一个LayoutAnimationController,并把 ...

  8. Android中使用抖动动画吸引来用户注意

    原文:http://www.androidcn.org/topic/552e65bc61d460226ab27a5c 在应用中,有时候我们要吸引用户去点击某些按钮,比如应用市场的推荐按钮,为了能够吸引 ...

  9. Android 中如何使用动画

    1:首先在res/anim/文件夹下建立动画xml文件. 2:在java代码中对UI控件使用动画. //加载动画 Animation myAnim=AnimationUtils.loadAnimati ...

随机推荐

  1. webpack多入口优化

    最近接手的项目是公司之前搭的多页面应用脚手架,然后到现在入口页面大大小小超过半百了,然后每次更新完配置之后,重启页面就贼拉卡,实在太影响开发效率了,于是开始优化呗. 最开始发现如果你想要让加载速度变快 ...

  2. Ubuntu---gcc && g++

    摘要:今天用 gcc 编译 c++ 代码,发现会报错:std::cout  这个函数无定义,所以决定查一下原因,在这里总结一下,虽然以后回头看一定会觉得太菜,但是新手期还是总要经历的一个阶段,所以就记 ...

  3. HTML5智能表单

    HTML5 智能表单 1.表单新增属性  ☀ autofocus 属性 <input type="text" autofocus/>设置 autofocus 属性,使文 ...

  4. centos查看自启动服务

    1,查看自启动服务? 2,查看某服务的开机启动状态? 3,启动(关闭,重启,查看)某个服务? 4,设置开机启动或者关闭某个服务? 1,查看自启动服务? systemctl list-unit-file ...

  5. pandas和re中正则表达式的意思

    这里()有两种意思,第一个就是表示匹配范围,另外一个就是输出这个匹配 下面那条语句就是告诉程序,是输出整个句子,“?:”非获取匹配,匹配冒号后的内容但不获取匹配结果,不进行存储供以后使用.

  6. Huawei BGP和OSPF双边界重分布(二)

    网络拓扑: 本例主要配置和例一致,主要是在AR3260-AR1和AR3260-AR2的路由域的边界上,从AR3260-AR1上重分布进BGP 65001的路由的时候打tag 650011,在AR326 ...

  7. Max answer(单调栈+ST表)

    Max answer https://nanti.jisuanke.com/t/38228 Alice has a magic array. She suggests that the value o ...

  8. odoo TransientModels must have log_access turned on

  9. Vue源码学习(二)$mount() 后的做的事(1)

    Vue实例初始化完成后,启动加载($mount)模块数据. (一)Vue$3.protype.$mount             标红的函数 compileToFunctions 过于复杂,主要是生 ...

  10. Python入门day04_函数与装饰器

    一.函数入门 什么是函数: # 函数:函数是一系列代码的集,用来完成特定功能的代码块,类似于工具,可以重复不但的去使用 为什么要有函数: # 优点:# 1. 避免代码的冗余 # 2. 让程序代码结构更 ...