Android 自定义SurfaceView实现加载GIF动画
来源:互联网 发布:2018中考倒计时软件 编辑:程序博客网 时间:2024/04/30 16:11
先看看实现效果:
SurfaceView类介绍:
进入源码:
public class SurfaceView extends View { public SurfaceView(Context context) { super((Context)null, (AttributeSet)null, 0, 0); throw new RuntimeException("Stub!"); } public SurfaceView(Context context, AttributeSet attrs) { super((Context)null, (AttributeSet)null, 0, 0); throw new RuntimeException("Stub!"); } public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super((Context)null, (AttributeSet)null, 0, 0); throw new RuntimeException("Stub!"); } public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super((Context)null, (AttributeSet)null, 0, 0); throw new RuntimeException("Stub!"); } public SurfaceHolder getHolder() { throw new RuntimeException("Stub!"); } protected void onAttachedToWindow() { throw new RuntimeException("Stub!"); } protected void onWindowVisibilityChanged(int visibility) { throw new RuntimeException("Stub!"); } public void setVisibility(int visibility) { throw new RuntimeException("Stub!"); } protected void onDetachedFromWindow() { throw new RuntimeException("Stub!"); } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { throw new RuntimeException("Stub!"); } public boolean gatherTransparentRegion(Region region) { throw new RuntimeException("Stub!"); } public void draw(Canvas canvas) { throw new RuntimeException("Stub!"); } protected void dispatchDraw(Canvas canvas) { throw new RuntimeException("Stub!"); } public void setZOrderMediaOverlay(boolean isMediaOverlay) { throw new RuntimeException("Stub!"); } public void setZOrderOnTop(boolean onTop) { throw new RuntimeException("Stub!"); } public void setSecure(boolean isSecure) { throw new RuntimeException("Stub!"); }}
从源码中可以看到:
SurfaceView 介绍
- SurfaceView 就是带 Surface 的 view,它是一个 View,是 View 的子类,所以和其他 View 一样,可以在屏幕上展示东西接收用户输入,具有 View 的生命周期回调函数,如 onMeasure、onLayout、onDraw、onTouchEvent 等
- SurfaceView 带有独立的 Surface(独立与 window 的 surface),这可以让子线程在独立的 Surface 上面绘制东西,进行 SurfaceView 的界面绘制,这个子线程就叫做渲染线程,但是要让独立的 Surface 上面的东西在 View 上面展示出来,需要 post 一个消息给主线程,目的是把该 Surface 中 canvas 上的东西绘制到 View 的真正的画布上面(window 的 surface 的 canvas上),这样就可以把 UI 线程空闲出来处理用户的交互
- Surface 可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated() 和 SurfaceHolder.Callback.surfaceDestroyed() 之间有效,这只是说 Surface 创建和销毁的时候会回到前面两个方法,所以要确保渲染线程访问的是合法有效的 surface
- SurfaceHolder.CallBack 是通过 SurfaceView 的 SurfaceHolder 的 addCallback 来设置给 SurfaceHolder 的,让 SurfaceView 实现 CallBack 并设置给 SurfaceHolder,SurfaceView 就可以监听这个独立 Surface 的创建和销毁了。
SurfaceHolder 介绍
上源码:
public interface SurfaceHolder { /** @deprecated */ @Deprecated int SURFACE_TYPE_GPU = 2; /** @deprecated */ @Deprecated int SURFACE_TYPE_HARDWARE = 1; /** @deprecated */ @Deprecated int SURFACE_TYPE_NORMAL = 0; /** @deprecated */ @Deprecated int SURFACE_TYPE_PUSH_BUFFERS = 3; void addCallback(SurfaceHolder.Callback var1); void removeCallback(SurfaceHolder.Callback var1); boolean isCreating(); /** @deprecated */ @Deprecated void setType(int var1); void setFixedSize(int var1, int var2); void setSizeFromLayout(); void setFormat(int var1); void setKeepScreenOn(boolean var1); Canvas lockCanvas(); Canvas lockCanvas(Rect var1); void unlockCanvasAndPost(Canvas var1); Rect getSurfaceFrame(); Surface getSurface(); public interface Callback2 extends SurfaceHolder.Callback { void surfaceRedrawNeeded(SurfaceHolder var1); } public interface Callback { void surfaceCreated(SurfaceHolder var1); void surfaceChanged(SurfaceHolder var1, int var2, int var3, int var4); void surfaceDestroyed(SurfaceHolder var1); } public static class BadSurfaceTypeException extends RuntimeException { public BadSurfaceTypeException() { throw new RuntimeException("Stub!"); } public BadSurfaceTypeException(String name) { throw new RuntimeException("Stub!"); } }}
SurfaceHolder 是对 SurfaceView 的 Surface 的包装,不但在 SurfaceHolder.callback 接口中负责 Surface 创建和销毁的回调,而且还对 Surface 的关键方法 LockCanvas()、unLockCanvasAndPost() 方法进行了线程安全的包装,所以 SurfaceHolder 是 Surface 对象的持有者,负责 Surface 的生命周期中的对 Surface 操作的方法的调用
脏矩形 Rect dirty,是指标记这块矩形区域的数据作废,也就是需要重写绘制的矩形区域,LockCanvas(Rect dirty),可以指定一个矩形区域,让 Surface 中的 Canvas 上部分数据重绘。
SurfaceView、SurfaceHolder、Surface 之间的关系
SurfaceView 使用的步骤
- 获取到 SurfaceView 对应的 SurfaceHolder,给 SurfaceHolder 添加一个 SurfaceHolder.callback 对象。
- 创建渲染线程对象
- 在子线程中开始在 Surface 上面绘制图形,因为SurfaceView没有对我们暴露 Surface,而只是暴露了 Surface 的包装器 SurfaceHolder,所以使用 SurfaceHolder 的 lockCanvas()获取 Surface 上面指定区域的 Canvas,在该 Canvas 上绘制图形,绘制结束后,使用 SurfaceHolder 的 unlockCanvasAndPost()方法解锁 Canvas,并且让 UI 线程把 Surface 上面的东西绘制到 View 的 Canvas 上面
自定义SurfaceView 实现GIF动画DEMO:
首先自定义class GifSurfaceView 继承SurfaceView,并实现SurfaceHolder.Callback接口,
详细代码如下:
public class GifSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; //gif图片路径 private String path; private Movie movie; //执行动画 private Handler handler; //放大倍数 private int zoom; //构造函数 public GifSurfaceView(Context context) { super(context); initParam(); } public GifSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); initParam(); } public GifSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initParam(); } //线程 private Runnable runnable = new Runnable() { @Override public void run() { //获取画布(加锁) Canvas canvas = holder.lockCanvas(); canvas.save(); canvas.scale(zoom,zoom); //x为水平方向的放大倍数,y为竖直方向的放大倍数。 //绘制此gif的某一帧,并刷新本身 movie.draw(canvas,0,0); //逐帧绘制图片(图片数量5) // 1 2 3 4 5 6 7 8 9 10 // 1 2 3 4 0 1 2 3 4 0 循环 movie.setTime((int) (System.currentTimeMillis()%movie.duration())); canvas.restore(); //结束锁定画图,并提交改变,画画完成(解锁) holder.unlockCanvasAndPost(canvas); handler.postDelayed(runnable , 50); //50ms表示每50ms绘制一帧 } }; /** * 初始化参数 */ private void initParam(){ holder = getHolder(); holder.addCallback(this); handler = new Handler(); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { } /** * 计算视图宽高 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //加载GIF图片 //1.获取GIF图片路径 if (!TextUtils.isEmpty(path)){ try { InputStream stream = getContext().getAssets().open(path); movie = Movie.decodeStream(stream); //获取gif的宽高 int width = movie.width(); int height = movie.height(); setMeasuredDimension((int)(width*zoom),(int)(height*zoom));// setMeasuredDimension(width,height); //执行gif动画 handler.post(runnable); } catch (IOException e) { e.printStackTrace(); } } } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { //停止gif动画 handler.removeCallbacks(runnable); } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public void setZoom(int zoom) { this.zoom = zoom; }@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {// TODO Auto-generated method stub}}/* * 整个过程:继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。*/
在MainActivity中进行调用并传入GIF路径:
public class MainActivity extends Activity {GifSurfaceView myView;int scale=1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myView=(GifSurfaceView)findViewById(R.id.gsv);//myView.setPath("a.gif");myView.setPath("2.gif");myView.setZoom(scale);}
总结:
第一步:继承SurfaceView并实现SurfaceHolder.Callback接口
第二步:SurfaceView.getHolder()获得SurfaceHolder对象
第三步:SurfaceHolder.addCallback(callback)添加回调函数
第四步:SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布
第五步:Canvas绘画
第六步:SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。
具体流程如下图所示:
源码下载
0 0
- Android 自定义SurfaceView实现加载GIF动画
- Android SurfaceView 实现Gif动画
- 自定义SurfaceView之加载GIF
- android加载gif动画 用动画实现
- android自定义SurfaceView实现跑男动画
- Android加载Gif动画实现代码
- Android 加载gif动画
- android加载GIF动画
- Android加载GIF动画
- Android SurfaceView实现动画
- Android的Gif动画加载
- 分享Android实现加载Gif动画的类库
- android 无任何依赖实现网络加载显示Gif动画
- android SurfaceView实现人物动画
- Android自定义加载动画的实现
- Android之gif动画实现
- 使用SurfaceView播放gif动画
- Android加载Gif动画android-gif-drawable的使用
- xcode7.0真机测试出现“Could not find Developer Disk Image"解决方法
- 课程回顾--AT89S51引脚功能
- 二叉排序树(二)
- Android studio 出现 Unsupported major.minor version 52.0
- 空间滤波
- Android 自定义SurfaceView实现加载GIF动画
- 337. House Robber III
- c++实验3—多分数段函数求值
- JS函数名加括号和不加括号的区别
- 多线程下单重判断懒汉式的低效原因分析及改进
- [C#]解决第三方控件引起的"类型Universe无法解析程序集"问题
- 求一元二次方程的实根或虚根
- freemarker生成java代码
- gcc编译选项学习