SurfaceView的使用
Posted Tears_fg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SurfaceView的使用相关的知识,希望对你有一定的参考价值。
1.概念
SurfaceView是View类的子类,可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图视图。它的特性是:可以在主线程之外的 线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背 景、人物、动画等等尽量在画布canvas中画出。
SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器。提供访问和控制SurfaceView背后的Surface 相关的方法 (providingaccess and control over this SurfaceView\'s underlying surface),它通过三个回调方法,让我们可以感知到Surface的创建、销毁或者改变。在SurfaceView中有一个方法getHolder,可以很方便地获得SurfaceView所对应的Surface所对应的SurfaceHolder
所有SurfaceView和SurfaceHolder.Callback中声明的方法,必须在运行SurfaceView窗口中的线程中调用(典型地,就是应用的主线程。译注:即UI线程),因为它们需要正确地将同时被绘制线程访问的各种状态进行同步
SurfaceView可见就会被创建,不可见就会被销毁
2.实现方法
1)实现步骤
a.继承SurfaceView
b.实现SurfaceHolder.Callback接口
2)需要重写的方法
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){} //在surface的大小发生改变时激发
(2)public void surfaceCreated(SurfaceHolder holder){} //在创建时激发,一般在这里调用画图的线程。
(3)public void surfaceDestroyed(SurfaceHolder holder) {} //销毁时激发,一般在这里将画图的线程停止、释放。
3)SurfaceHolder
SurfaceHolder,surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。
几个需要注意的方法:
(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 给SurfaceView当前的持有者一个回调对象。
(2)、abstract Canvas lockCanvas();
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。
// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 结束锁定画图,并提交改变。
4)总结整个过程
继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数 ---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。
实例一:
画圆:在xml文件中引用自定义SurfaceVIew就ok了
/** *按下home键,页面不可见 * Created by Administrator on 2016/10/3. */ public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{ private final SurfaceHolder holder; private Paint paint; private MyThread thread; private boolean isDraw = false; public MySurfaceView(Context context, AttributeSet attrs) { super(context, attrs); holder = this.getHolder(); holder.addCallback(this); //创建画笔 createPaint(); } private void createPaint() { paint = new Paint(); paint.setColor(Color.BLUE); paint.setAntiAlias(true); //设置画的样式为画边框 paint.setStyle(Paint.Style.STROKE); } /** *页面可见调用 * @param holder */ @Override public void surfaceCreated(SurfaceHolder holder) { //创建一个绘图线程 thread = new MyThread(); isDraw = true; thread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * surfaceView页面不可见调用 * @param holder */ @Override public void surfaceDestroyed(SurfaceHolder holder) { //该方法在主线程中运行 isDraw = false; Log.i("tag", "surfaceDestroyed: "); //join方法,阻塞线程,只有当当前线程执行完,才会执行其他线程的方法 try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } class MyThread extends Thread{ private int radius = 10; @Override public void run() { while(isDraw){ Log.i("tag", "run: "+Thread.currentThread().getName()); //同步,避免不同线程在同一个画布上进行绘画操作 synchronized (holder){ //锁定画布 Canvas canvas = holder.lockCanvas(); //第一次进入和退出程序时,canvas为空 if(canvas != null) { //画圆 canvas.drawCircle(100, 100, radius, paint); radius += 10; if (radius > 70) { radius += 3; } // 睡眠,时间不能太长,否则和join方法会产生冲突 SystemClock.sleep(50); //解锁画布,并提交 holder.unlockCanvasAndPost(canvas); } } } } } }
join和sleep的区别:
实例二:
调用摄像头进行拍照:
需要权限:
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private SurfaceView surfaceView; private ImageView image; private SurfaceHolder holder; private Camera camera; private boolean isDraw = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = (SurfaceView) findViewById(R.id.surfaceView); image = (ImageView) findViewById(R.id.image); holder = surfaceView.getHolder(); holder.addCallback(this); //打开照相机 camera = Camera.open(0); } public void onTakePhotos(View view){ /*参数1: 回调 *参数2: 原图片回调 * 参数3: jpg格式图片回调 * */ camera.takePicture(null, null, new Camera.PictureCallback() { /*data就是图片的字节形式的数据*/ @Override public void onPictureTaken(byte[] data, Camera camera) { surfaceView.setVisibility(View.GONE); image.setVisibility(View.VISIBLE); image.setImageBitmap(BitmapFactory.decodeByteArray(data,0,data.length)); } }); } /*当surfaceView可见的时候调用*/ @Override public void surfaceCreated(SurfaceHolder holder) { try { //设置预览参数,与 surfaceView绑定 camera.setPreviewDisplay(holder); //设置显示的布局为垂直 camera.setDisplayOrientation(90); //开启预览 camera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /*当surfaceView不可见的时候调用*/ @Override public void surfaceDestroyed(SurfaceHolder holder) { if(camera != null) { // camera.release(); camera.stopPreview(); } } }
效果图:
播放gif图片:在main--new dir--asserts文件夹,将图片放入
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{ private SurfaceView surfaceView; private Movie movie; private SurfaceHolder surfaceHolder; private boolean flag; private MyThread myThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = (SurfaceView) findViewById(R.id.surfaceView); //获得surfaceView的holder对象 surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); try { //将gif图片拆分成一帧一帧的资源 movie = Movie.decodeStream(getResources().getAssets().open("new.gif")); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceCreated(SurfaceHolder holder) { flag = true; // 开启线程播放gif图片 myThread = new MyThread(); myThread.start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { //销毁该线程 flag = false; try { myThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } class MyThread extends Thread{ @Override public void run() { super.run(); long startTime = System.currentTimeMillis(); while(flag){ synchronized (surfaceHolder){ //锁定画板 Canvas canvas = surfaceHolder.lockCanvas();
if(canvas != null){ //gif的播放的总时间 int duration = movie.duration();
Paint paint = new Paint(); //得到当前时间 long currentTime = System.currentTimeMillis(); // 计算当前应该播放到的位置 设置该时间点播放的帧 movie.setTime((int) ((currentTime-startTime)%duration)); //画 movie.draw(canvas,200,200,null); //解锁画板 surfaceHolder.unlockCanvasAndPost(canvas); } } } } } }
效果
转自:
Android之SurfaceView使用总结
以上是关于SurfaceView的使用的主要内容,如果未能解决你的问题,请参考以下文章