资源预览内容
第1页 / 共18页
第2页 / 共18页
第3页 / 共18页
第4页 / 共18页
第5页 / 共18页
第6页 / 共18页
第7页 / 共18页
第8页 / 共18页
第9页 / 共18页
第10页 / 共18页
亲,该文档总共18页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
android的图像图像-SurfaceView类,2017/12/30,View和SurfaceView,View类是android的一个超类,每一个View都有一个用于绘画的画布,这个画布可以进行任意的扩展。有的时候我们需要自定义VIew实现自己想要的视图。view、SurfaceView是游戏开发中经常用到的视图。View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面,速度较慢。SurfaceView:基于view视图进行拓展的视图类,更适合2D游戏的开发;是view的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面速度比view快。,View的缺陷,View缺乏双缓冲机制当程序需要更新View上的图像时,必须重绘View上显示的整张图片。,SurfaceView 类,SurfaceView是从View基类中派生出来的显示类,直接子类有GLSurfaceView和VideoView,GL和视频播放以及Camera摄像头一般均使用SurfaceView. SurfaceView可以控制表面的格式,比如大小、显示在屏幕中的位置,最关键是的提供了SurfaceHolder类,使用getHolder方法获取,相关的方法有 lockCanvas()、 lockCanvas(Rect dirty) 、 removeCallback(Callback callback)、 unlockCanvasAndPost(Canvas canvas) 控制图形以及绘制。对于Surface,Android底层还提供了GPU加速功能,所以一般实时性很强的应用中主要使用SurfaceView而不是直接从View 构建,同时Android后面用到的OpenGL中的GLSurfaceView也是从该类实现。,2017/12/30,callback接口,只要继承SurfaceView类并实现SurfaceHolder.Callback接口就可以实现一个自定义的SurfaceView,SurfaceHolder.Callback在底层的Surface状态发生变化的时候通知View,SurfaceHolder.Callback具有如下的接口:surfaceCreated(SurfaceHolder holder):当Surface第一次创建后会立即调用该函数。程序可以在该函数中做些和绘制界面相关的初始化工作,一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中绘制Surface。surfaceChanged(SurfaceHolder holder, int format, int width,int height):当Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。,注意:一个SurfaceView只在SurfaceHolder.Callback.surfaceCreated() 和 SurfaceHolder.Callback.surfaceDestroyed()调用之间是可用的,其他时间是得不到它的Canvas对象的(null)。,Android-surfaceView 与View 的区别,SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。那么在UI的主线程中更新画面 可能会引发问题,比如更新画面的时间过长,那么主UI线程会被正在绘制的函数阻塞。那么将无法响应按键、触屏等消息。使用surfaceView ,由于是在新的线程中更新画面所以不会阻塞UI主线程。但这也带来了另外一个问题,就是事件同步。比如触屏了一下,需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。所以基于以上,根据游戏特点,一般分成两类:(1 )被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。(2 )主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞主线程。所以显然view不合适,需要surfaceView来控制。,使用SurfaceView绘制矩形,2017/12/30,public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(new MyView(this); ,class MyView extends SurfaceView implements SurfaceHolder.Callback SurfaceHolder holder;public MyView(Context context) super(context);holder=getHolder();holder.addCallback(this);,public void surfaceCreated(SurfaceHolder holder) new Thread(new MyThread().start();,使用SurfaceView绘制矩形,2017/12/30,class MyThread implements Runnablepublic void run() /锁定画布,通过其返回的画布对象canvas,在其上面画图Canvas canvas=holder.lockCanvas(); canvas.drawColor(Color.WHITE);Paint paint=new Paint();paint.setColor(Color.YELLOW);canvas.drawRect(10, 10, 220, 180, paint);holder.unlockCanvasAndPost(canvas);/结束锁定画图,并提交编辑,SurfaceView绘图机制,重写CallBack对象的surfaceCreate方法,在该方法中为SurfaceView绘制背景,并避免背景图片被下一次lockCanvas遮挡。监听触摸事件,每次触摸屏幕时,程序会锁定触碰周围的区域,那么就只更新该区域的数据,而且本次的lockCanvas会遮挡上一次的lockCanvas后绘制的图形。注:第一次绘制的图形可能会被第二次的lockCanvas遮挡,第三次的lockcanvas又可能遮挡第二次lockCanvas的区域,但不可能遮挡第一次的lockCanvas区域,SurfaceView绘图机制,2017/12/30,holder.addCallback(new Callback() public void surfaceDestroyed(SurfaceHolder holder) public void surfaceCreated(SurfaceHolder holder) Canvas canvas=holder.lockCanvas();Bitmap bitmap=BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.sun);canvas.drawBitmap(bitmap, 0, 0, null);holder.unlockCanvasAndPost(canvas);holder.lockCanvas(new Rect(0,0,0,0);holder.unlockCanvasAndPost(canvas);public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) );,SurfaceView绘图机制,2017/12/30,sf.setOnTouchListener(new OnTouchListener() public boolean onTouch(View v, MotionEvent event) if(event.getAction()=MotionEvent.ACTION_DOWN)int cx=(int) event.getX();int cy=(int) event.getY();Canvas canvas=holder.lockCanvas(new Rect(cx-50,cy-50,cx+50,cy+50);canvas.save();canvas.rotate(30, cx, cy);paint.setColor(Color.YELLOW);canvas.drawRect(cx-40, cy-40, cx, cy, paint);canvas.restore();paint.setColor(Color.GREEN);canvas.drawRect(cx, cy, cx+40, cy+40, paint);holder.unlockCanvasAndPost(canvas);return false;);,SurfaceView的双缓冲使用,2017/12/30,前面简单介绍了SurfaceView的使用,这次就介绍SurfaceView的双缓冲使用。双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,另一个专门绘图:,对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高双缓冲的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。,SurfaceView的双缓冲使用,Button btn1, btn2;SurfaceView sfv;SurfaceHolder sfh;ArrayList imglist = new ArrayList();int imgwidth, imgheight;Bitmap bitmap; public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.main); btn1 = (Button) this.findViewById(R.id.btn1);btn2 = (Button) this.findViewById(R.id.btn2);btn1.setOnClickListener(new MyListener();btn2.setOnClickListener(new MyListener();sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);sfh = sfv.getHolder();sfh.addCallback(new MyCallBack();/ 自动运行surfaceCreated ,
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号