首先定义一些需要的属性,用于在布局文件中设置gif
然后定义Gif的播放监听器,来监听各个时段的事件,命名的含义都很简单就不再介绍了:
public interface OnPlayListener {
void onPlayStart();
void onPlaying(int percent);
void onPlayPause(boolean pauseSuccess);
void onPlayRestart();
void onPlayEnd();
}
声明类,直接继承ImageView,这样我们不仅可以显示Gif动画,也可以显示普通图片:
public class GifImageView extends AppCompatImageView
然后加载Gif图片资源
public void setGifResource(int movieResourceId, OnPlayListener onPlayListener) {
mOnPlayListener = onPlayListener;
movie = Movie.decodeStream(getResources().openRawResource(movieResourceId));
if (movie == null) {
//如果movie为空,那么就不是gif文件,尝试转换为bitmap显示
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), movieResourceId);
if (bitmap != null) {
setImageBitmap(bitmap);
return;
}
}
movieDuration = movie.duration() == 0 ? DEFAULT_DURATION : movie.duration();
requestLayout();
}
调用requestLayout重新计算View大小,并重新绘制。如果是gif格式则View宽高等于movie的宽高,不是则调用父类的测量方法。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (movie != null) {
int movieWidth = movie.width();
int movieHeight = movie.height();
setMeasuredDimension(movieWidth, movieHeight);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
开始播放,其实就是调用invalidate从而调用onDraw方法就行UI绘制:
public void play(int counts) {
this.counts = counts;
reset();
if (mOnPlayListener != null) {
mOnPlayListener.onPlayStart();
}
invalidate();
}
不断调用onDraw方法来绘制Gif当前时间的图片帧(同样需要判断是否是gif格式,不是则调用父类的绘制方法):
@Override
protected void onDraw(Canvas canvas) {
if (movie != null) {
if (!mPaused && hasStart) {
drawMovieFrame(canvas);
invalidateView();
} else {
drawMovieFrame(canvas);
}
} else {
super.onDraw(canvas);
}
}
/**
- 画出gif帧
*/
private void drawMovieFrame(Canvas canvas) {
movie.setTime(getCurrentFrameTime());
movie.draw(canvas, 0.0f, 0.0f);
}
最核心的方法就是计算当前时间需要绘制处于movie中的对应时间的图片帧。
private int getCurrentFrameTime() {
if (movieDuration == 0)
return 0;
//因为有暂停,所以需要减去暂停时间
long now = SystemClock.uptimeMillis() - dealyTime;
int nowCount = (int) ((now - mMovieStart) / movieDuration);
if (counts != -1 && nowCount >= counts) {
hasStart = false;
if (mOnPlayListener != null) {
mOnPlayListener.onPlayEnd();
}
}
int currentTime = (int) ((now - mMovieStart) % movieDuration);
int percent = currentTime * 100 / movieDuration;
if (mOnPlayListener != null && hasStart) {
mOnPlayListener.onPlaying(percent);
}
return currentTime;
}
暂停Gif播放:
public void pause() {
if (movie != null && !mPaused && hasStart) {
mPaused = true;
invalidate();
mMoviePauseTime = SystemClock.uptimeMillis();
if (mOnPlayListener != null) {
mOnPlayListener.onPlayPause(true);
}
} else {
if (mOnPlayListener != null) {
mOnPlayListener.onPlayPause(false);
}
}
}
继续Gif播放:
if (mPaused && mMoviePauseTime > 0) {
mPaused = false;
dealyTime = dealyTime + SystemClock.uptimeMillis() - mMoviePauseTime;
invalidate();
if (mOnPlayListener != null) {
mOnPlayListener.onPlayRestart();
}
}
尾声
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。
- 思维脑图
- 性能优化学习笔记
- 性能优化视频
当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。
.(img-kMPh2y1P-1718868527646)]
[外链图片转存中…(img-hKBN4Ckh-1718868527646)]
- 性能优化视频
[外链图片转存中…(img-BS4VGteV-1718868527646)]
当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。