• Android自定义组件系列【12】——非UI线程绘图SurfaceView


    一、SurfaceView的介绍

    在前面我们已经会自定义View,使用canvas绘图,但是View的绘图机制存在一些缺陷。

    1、View缺乏双缓冲机制。

    2、程序必须重绘整个View上显示的图片,比较耗资源。

    3、非UI线程无法更新View组件,所以会占用主线程资源,当需要在主线程中处理逻辑的时候会很慢。

    在Android中为我们提供了一个SurfaceView来替代View实现绘制图形,一般在游戏绘图方面应用较广,所以如果是比较复杂的绘图建议使用SurfaceView.

    二、SurfaceView的绘图机制

    SurfaceView一般会与SurfaceHolder结合使用,SurfaceHolder用于与之关联的SurfaceView上绘图,调用SurfaceView的getHolder()方法可获取SurfaceView关联的SurfaceHolder.
    SurfaceHolder提供了lockCanvas和lockCanvas(Rect dirty)来锁定绘图区域,并获取到该区域的画布(Canvas)我们通过该画布就可以进行图形的绘制了。

    三、SurfaceView使用实例

    1、一个简单的使用(绘制在UI线程)
    package com.test.surfaceview;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.os.Bundle;
    import android.view.MotionEvent;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnTouchListener;
    
    import com.example.testsurfaceview.R;
    
    public class MainActivity extends Activity{
    	
    	private SurfaceHolder holder;
    	private Paint paint;
    	private Rect rect;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		
    		paint = new Paint();
    		rect = new Rect();
    		
    		SurfaceView surface = (SurfaceView)findViewById(R.id.show);
    		holder = surface.getHolder();
    		
    		//由系统毁掉的三个函数
    		holder.addCallback(new SurfaceHolder.Callback() {
    			
    			@Override
    			public void surfaceDestroyed(SurfaceHolder holder) {
    			}
    			
    			@Override
    			public void surfaceCreated(SurfaceHolder holder) {
    				Canvas canvas = holder.lockCanvas();
    				Bitmap bitmap = BitmapFactory.decodeResource(
    						MainActivity.this.getResources(), R.drawable.ic_launcher);
    				canvas.drawBitmap(bitmap, 0, 0, null);
    				holder.unlockCanvasAndPost(canvas);
    			}
    			
    			@Override
    			public void surfaceChanged(SurfaceHolder holder, int format, int width,
    					int height) {
    			}
    		});
    		
    		//绑定事件监听
    		surface.setOnTouchListener(new OnTouchListener() {
    			
    			@Override
    			public boolean onTouch(View v, MotionEvent event) {
    				if(event.getAction() == MotionEvent.ACTION_DOWN){
    					int cx = (int)event.getX();
    					int cy = (int)event.getY();
    					
    					rect.set(cx - 50, cy - 50, cx + 50, cy + 50);
    					//锁定一个固定区域并锁定
    					Canvas canvas = holder.lockCanvas(rect);
    					//保存画布当前状态
    					canvas.save();
    					//旋转画布
    					canvas.rotate(30, cx, cy);
    					paint.setColor(Color.RED);
    					//绘制方块
    					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;
    			}
    		});
    	}
    }
    
    2、在非UI线程中绘制
    package com.test.surfaceview;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.os.AsyncTask;
    import android.util.AttributeSet;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    
    import com.example.testsurfaceview.R;
    
    /**
     * 阳光小强 http://blog.csdn.net/dawanganban
     * 
     * @author Administrator
     * 
     */
    public class MySurfaceView extends SurfaceView {
    
    	private Context context;
    	private Rect rect;
    	private Paint paint;
    
    
    	private AppStartDrawView appStartDrawView;
    
    	public MySurfaceView(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		this.context = context;
    		rect = new Rect();
    		paint = new Paint();
    		appStartDrawView = new AppStartDrawView();
    		this.getHolder().addCallback(appStartDrawView);
    	}
    
    	/**
    	 * 停止动画
    	 */
    	public void stopAnim() {
    		appStartDrawView.cancel(true);
    	}
    
    	private class AppStartDrawView extends AsyncTask<Void, Integer, Void> implements SurfaceHolder.Callback {
    		private boolean isStarted = false;
    		private SurfaceHolder holder;
    
    		@Override
    		public void surfaceCreated(SurfaceHolder holder) {
    			this.holder = holder;
    			
    			//绘制一个图片
    			Canvas canvas = holder.lockCanvas();
    			Bitmap bitmap = BitmapFactory.decodeResource(
    					context.getResources(), R.drawable.ic_launcher);
    			canvas.drawBitmap(bitmap, 0, 0, null);
    			holder.unlockCanvasAndPost(canvas);
    			
    			if (!isStarted) {
    				this.execute();
    				isStarted = true;
    			}
    		}
    
    		@Override
    		public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    			this.holder = holder;
    		}
    
    		@Override
    		public void surfaceDestroyed(SurfaceHolder holder) {
    			isStarted = false;
    			holder = null;
    		}
    		
    
    		@Override
    		protected Void doInBackground(Void... params) {
    			int cx = 0;
    			int cy = 0;
    			while(!isCancelled()){
    				//绘制动画
    				//TODO .....
    				rect.set(cx - 50, cy - 50, cx + 50, cy + 50);
    				//锁定一个固定区域并锁定
    				Canvas canvas = holder.lockCanvas(rect);
    				//保存画布当前状态
    				canvas.save();
    				//旋转画布
    				canvas.rotate(30, cx, cy);
    				paint.setColor(Color.RED);
    				//绘制方块
    				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);
    				
    				//TODO ....
    				try {
    					Thread.sleep(1000);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				cx += 60;
    				cy += 60;
    				
    				if(cx  >= 400){
    					stopAnim();
    				}
    			}
    			return null;
    		}
    
    	}
    }
  • 相关阅读:
    Java中使用Log4j记录错误、输出日志
    oracle 触发器的实例(转)
    [jsp学习笔记]servelt get post
    [winfrom]C#中使用SendMessage
    3)创建,测试,发布 第一个NET CORE程序
    DDL和DML 的区别
    [jsp学习笔记] jsp过滤器
    [jsp学习笔记] jsp基础知识 数据初始化、同步
    [jsp学习笔记]jstl标签的使用
    LiteORM-For-DotNet,我的第一个开源库……更新
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468603.html
Copyright © 2020-2023  润新知