TouchPaint 绘图学习

这是API Demo中的一个例子,效果图如上,代码如下:

public class TouchPaint extends Activity{
	/**Used as a pluse to gradually fade the contents of the window*/
	private static final int FADE_MSG = 1;
	
	/**Menu ID for the command to clear the window*/
	private static final int CLEAR_ID = Menu.FIRST;
	/**Menu ID for the command to toggle fading*/
	private static final int FADE_ID = Menu.FIRST + 1;
	
	/**How often to fade the contents of the window(in ms)*/
	private static final int FADE_DELAY = 100;
	
	/**The view responsible for drawing the window*/
	private TouchPaintView mTouchPaintView;
	
	/**Is fading mode enabled?*/
	private boolean mFading;
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		mTouchPaintView = new TouchPaintView(this);
		setContentView(mTouchPaintView);
		mTouchPaintView.requestFocus();
		
		mFading = savedInstanceState != null ? savedInstanceState.getBoolean("fading", true) : true;
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		// TODO Auto-generated method stub
		super.onSaveInstanceState(outState);
		
		outState.putBoolean("fading", true);
	}
	
	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		if(mFading){
			startFading();
		}
	}
	

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
	
		stopFading();
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, CLEAR_ID, 0, "Clear");
		menu.add(0, FADE_ID, 0, "Fade");
		return super.onCreateOptionsMenu(menu);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case CLEAR_ID:
			mTouchPaintView.clear();
			break;
		case FADE_ID:
			mFading = !mFading;
			if(mFading){
				stopFading();
			}else {
				startFading();
			}
			break;
		default:
			break;
		}
		return super.onOptionsItemSelected(item);
	}

	private void stopFading() {
		mHandler.removeMessages(FADE_MSG);
	}
	
	private void startFading() {
		mHandler.removeMessages(FADE_MSG);
		mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_MSG), FADE_DELAY);
	}
	
	private Handler mHandler  = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			//Upon receiving the fade pulse,we have the view perform a 
			//fade and then enqueue a new message to pulse at the desired next time
			case FADE_MSG:
				mTouchPaintView.fade();
				mHandler.sendEmptyMessageDelayed(FADE_MSG, FADE_DELAY);
				break;
			default:
				break;
			}
			
		};
	};
}

class TouchPaintView extends View{
	private static final int FADE_ALPHA = 0x06;
	private static final int MAX_FADE_STEPS = 256/FADE_ALPHA + 4;
	private Bitmap mBitmap;
	private Canvas mCanvas;
	private Paint mPaint;
	private Paint mFadePaint;
	private Rect mRect = new Rect();
	private boolean mCurDown;
	private int mCurX;
	private int mCurY;
	private float mCurPressure;
	private float mCurSize;
	private int mCurWidth;
	private int mFadeStepsIndex = MAX_FADE_STEPS;

	public TouchPaintView(Context context) {
		super(context);
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setARGB(255, 255, 255, 255);
		mFadePaint = new Paint();
		mFadePaint.setDither(true);
		mFadePaint.setARGB(FADE_ALPHA, 0, 0, 0);
	}

	public void clear() {
		if (null != mCanvas) {
			mPaint.setARGB(0xff, 0, 0, 0);
			//Fill the entire canvas' bitmap (restricted to the current clip) with the specified paint.
			//This is equivalent (but faster) to drawing an infinitely large rectangle with the specified paint.
			mCanvas.drawPaint(mPaint);
			invalidate();
			mFadeStepsIndex = MAX_FADE_STEPS;
		}
	}

	public void fade() {
		if (null != mCanvas &&mFadeStepsIndex <= MAX_FADE_STEPS) {
			mCanvas.drawPaint(mFadePaint);
			invalidate();
			mFadeStepsIndex++;
		}
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		int curW = mBitmap != null ? mBitmap.getWidth() : 0;
		int curH = mBitmap != null ? mBitmap.getHeight() : 0;
		if (curW > w && curH > h) {
			return;
		}
		
		if (curW < w) {
			curW = w;
		}
		if (curH <h) {
			curH = h;
		}
		
		Bitmap newBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.RGB_565);
		Canvas newCanvas = new Canvas();
		//Specify a bitmap for the canvas to draw into.
		newCanvas.setBitmap(newBitmap);
		mBitmap = newBitmap;
		mCanvas = newCanvas;
		mFadeStepsIndex = MAX_FADE_STEPS;
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		if (null != mBitmap) {
			canvas.drawBitmap(mBitmap, 0, 0, mPaint);
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		mCurDown = (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE);
		int N = event.getPointerCount();
		for (int i = 0; i < N; i++) {
			drawCircle(event.getHistoricalX(i), event.getHistoricalY(i),
					event.getHistoricalPressure(i), event.getHistoricalSize(i));
		}
		drawCircle(event.getX(), event.getY(), event.getPressure(), event.getSize());
		return true;
	}
	
	private void drawCircle(float x, float y, float pressure, float size){
		mCurX = (int)x;
		mCurY = (int)y;
		mCurPressure = pressure;
		mCurSize = size;
		mCurWidth = (int)(mCurSize*(getWidth()/3));
		if(mCurWidth < 1){
			mCurWidth = 1;
		}
		if (mCurDown && null != mBitmap) {
			int pressureLevel = (int)(mCurPressure * 255);
			mPaint.setARGB(pressureLevel, 255, 255, 255);
			mCanvas.drawCircle(mCurX, mCurY, mCurWidth, mPaint);
			mRect.set(mCurX - mCurWidth -2, mCurY - mCurWidth -2,
					mCurX + mCurWidth +2, mCurY + mCurWidth +2);
			invalidate(mRect);
		}
		mFadeStepsIndex = 0;
	}
	
	
}
备注一:

理解这个程序的关键是明白Bitmap、Canvas、Paint之间的关系。

Bitmap mBitmap = Bitmap.createBitmap(curW, curH, Bitmap.Config.RGB_565);
Canvas mCanvas = new Canvas();
//Specify a bitmap for the canvas to draw into.
mCanvas.setBitmap(mBitmap);
这里就可以理解为这个mCanvas和mBitmap绑定了,我以后用mCanvas画的东西都是画到mBitmap上的,然后不管之前是画的什么最后在onDraw的时候,我只要画出这个bitmap就可以了,即使画这个mBitmap的不是原来的mCanvas,因为我的mBitmap上已经有mCanvas画上的东西了。

@Override
	protected void onDraw(Canvas canvas) {
		if (null != mBitmap) {
			canvas.drawBitmap(mBitmap, 0, 0, mPaint);
		}
	}
备注二:

在程序中我可以清空整个画布的内容,也可以设置是是否渐变的效果,这都是通过设置mCanvas的Paint来实现的

public void clear() {
		if (null != mCanvas) {
			mPaint.setARGB(0xff, 0, 0, 0);
			//Fill the entire canvas' bitmap (restricted to the current clip) with the specified paint.
			//This is equivalent (but faster) to drawing an infinitely large rectangle with the specified paint.
			mCanvas.drawPaint(mPaint);
			invalidate();
			mFadeStepsIndex = MAX_FADE_STEPS;
		}
	}

	public void fade() {
		if (null != mCanvas &&mFadeStepsIndex <= MAX_FADE_STEPS) {
			mCanvas.drawPaint(mFadePaint);
			invalidate();
			mFadeStepsIndex++;
		}
	}
以上面的清空画布为例:当将画笔设置成透明黑色mPaint.setARGB(0xff, 0, 0, 0);,然后mCanvas.drawPaint(mPaint);,关键弄明白API中的解释:

//Fill the entire canvas' bitmap (restricted to the current clip) with the specified paint.
//This is equivalent (but faster) to drawing an infinitely large rectangle with the specified paint.
mCanvas.drawPaint(mPaint);

也就是将mCanvas的bitmap设置成指定画笔,下面的渐变效果也是这样设置的

你可能感兴趣的:(command,null,action,float,menu,delay)