Drawing shapes with fingers
It is very simple to draw basic shapes with fingers.
As always, it is just an example, you can improve it in many ways.
First of all we need a custom
Then we can define the paint object.
The
For example:
The last steps are to override the
We can apply the same logic to draw lines,straight lines, circles, squares, rectangles, triangles....
When we are drawing with fingers we can override the onTouchEvent:
With this event we can store the initial point. It will be useful in the following steps. When we are moving the finger we will receive a
In all cases, we will prepare the view to be drawn, and we will call the invalidate() method to call the onDraw() method.
Something like this:
If you would like a square, the example is very similar.
A square can be a particular rectangle where the base = height.
With a similar structure we can do something like this:
If you would like to draw a circle, you have to calculate the radius:
Let's try to draw a line. In this case we will use a Path.
A triangle needs 3 points.
With our logic we can draw the base of the triangle. Then with a 3th touch we can move along the height and draw the other 2 sides.
Here you can find a small video to see this code in action.
You can get code from GitHub:
As always, it is just an example, you can improve it in many ways.
First of all we need a custom
View
.
public class DrawingView extends View { }Then we will use a Bitmap, a Canvas and a Paint ojbects:
protected Paint mPaint; protected Bitmap mBitmap; protected Canvas mCanvas;To initialize the bitmap and the canvas, we can override this method in our View:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); }If you need to create a new Canvas, you must define the Bitmap upon which drawing will actually be performed. The Bitmap is always required for a Canvas.
Then we can define the paint object.
The
Paint
holds the information about the style and the color which we will use to draw.
For example:
public DrawingView(Context context) { super(context); init(); } protected void init() { mPaint = new Paint(Paint.DITHER_FLAG); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(getContext().getResources().getColor(android.R.color.holo_blue_dark)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(TOUCH_STROKE_WIDTH); }Here you can use your favorite style.
The last steps are to override the
onDraw()
and onTouchEvent()
methods in our custom view.
We can apply the same logic to draw lines,straight lines, circles, squares, rectangles, triangles....
When we are drawing with fingers we can override the onTouchEvent:
@Override public boolean onTouchEvent(MotionEvent event) { //Retrieve the point mx = event.getX(); my = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //First touch . Store the initial point invalidate(); case MotionEvent.ACTION_MOVE: //We are drawing. invalidate(); case MotionEvent.ACTION_UP: //We are finishing the draw. Draw on canvas. invalidate(); } return true; }When we start to draw we will receive a
MotionEvent.ACTION_DOWN
event. With this event we can store the initial point. It will be useful in the following steps. When we are moving the finger we will receive a
MotionEvent.ACTION_MOVE
event.
When we take off the finger we will receive a MotionEvent.ACTION_UP
event.
In all cases, we will prepare the view to be drawn, and we will call the invalidate() method to call the onDraw() method.
Something like this:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mBitmap, 0, 0, mPaint); //draw your element }Let's start with a rectangle:
@Override public boolean onTouchEvent(MotionEvent event) { mx = event.getX(); my = event.getY(); switch (mCurrentShape) { case RECTANGLE: onTouchEventRectangle(event); break; } return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mBitmap, 0, 0, mPaint); if (isDrawing){ switch (mCurrentShape) { case RECTANGLE: onDrawRectangle(canvas); break; } } }
//------------------------------------------------------------------ // Rectangle //------------------------------------------------------------------ private void onTouchEventRectangle(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isDrawing = true; mStartX = mx; mStartY = my; invalidate(); break; case MotionEvent.ACTION_MOVE: invalidate(); break; case MotionEvent.ACTION_UP: isDrawing = false; drawRectangle(mCanvas,mPaintFinal); invalidate(); break; } } private void onDrawRectangle(Canvas canvas) { drawRectangle(canvas,mPaint); } private void drawRectangle(Canvas canvas,Paint paint){ float right = mStartX > mx ? mStartX : mx; float left = mStartX > mx ? mx : mStartX; float bottom = mStartY > my ? mStartY : my; float top = mStartY > my ? my : mStartY; canvas.drawRect(left, top , right, bottom, paint); }Now you can start to draw your rectangle moving your fingers.
If you would like a square, the example is very similar.
A square can be a particular rectangle where the base = height.
With a similar structure we can do something like this:
//------------------------------------------------------------------ // Square //------------------------------------------------------------------ private void onDrawSquare(Canvas canvas) { onDrawRectangle(canvas); } private void onTouchEventSquare(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isDrawing = true; mStartX = mx; mStartY = my; invalidate(); break; case MotionEvent.ACTION_MOVE: adjustSquare(mx, my); invalidate(); break; case MotionEvent.ACTION_UP: isDrawing = false; adjustSquare(mx, my); drawRectangle(mCanvas,mPaintFinal); invalidate(); break; } } /** * Adjusts current coordinates to build a square * @param x * @param y */ protected void adjustSquare(float x, float y) { float deltaX = Math.abs(mStartX - x); float deltaY = Math.abs(mStartY - y); float max = Math.max(deltaX, deltaY); mx = mStartX - x < 0 ? mStartX + max : mStartX - max; my = mStartY - y < 0 ? mStartY + max : mStartY - max; }The only difference is the method
adjustSquare
where we modify the coordinate of point(mx,my) where we are moving to achieve a square.
If you would like to draw a circle, you have to calculate the radius:
//------------------------------------------------------------------ // Circle //------------------------------------------------------------------ private void onDrawCircle(Canvas canvas){ canvas.drawCircle(mStartX, mStartY, calculateRadius(mStartX, mStartY, mx, my), mPaint); } private void onTouchEventCircle(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isDrawing = true; mStartX = mx; mStartY = my; invalidate(); break; case MotionEvent.ACTION_MOVE: invalidate(); break; case MotionEvent.ACTION_UP: isDrawing = false; mCanvas.drawCircle(mStartX, mStartY, calculateRadius(mStartX,mStartY,mx,my), mPaintFinal); invalidate(); break; } } /** * * @return */ protected float calculateRadius(float x1, float y1, float x2, float y2) { return (float) Math.sqrt( Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) ); }Let's try to draw a straight line:
//------------------------------------------------------------------ // Line //------------------------------------------------------------------ private void onDrawLine(Canvas canvas) { float dx = Math.abs(mx - mStartX); float dy = Math.abs(my - mStartY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { canvas.drawLine(mStartX, mStartY, mx, my, mPaint); } } private void onTouchEventLine(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isDrawing = true; mStartX = mx; mStartY = my; invalidate(); break; case MotionEvent.ACTION_MOVE: invalidate(); break; case MotionEvent.ACTION_UP: isDrawing = false; mCanvas.drawLine(mStartX, mStartY, mx, my, mPaintFinal); invalidate(); break; } }Finally the two cases more complicated.
Let's try to draw a line. In this case we will use a Path.
//------------------------------------------------------------------ // Smooth Line //------------------------------------------------------------------ private void onTouchEventSmoothLine(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isDrawing = true; mStartX = mx; mStartY = my; mPath.reset(); mPath.moveTo(mx, my); invalidate(); break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(mx - mStartX); float dy = Math.abs(my - mStartY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mStartX, mStartY, (mx + mStartX) / 2, (my + mStartY) / 2); mStartX = mx; mStartY = my; } mCanvas.drawPath(mPath, mPaint); invalidate(); break; case MotionEvent.ACTION_UP: isDrawing = false; mPath.lineTo(mStartX, mStartY); mCanvas.drawPath(mPath, mPaintFinal); mPath.reset(); invalidate(); break; } }Then a triangle. In this case we have to change something in our logic.
A triangle needs 3 points.
With our logic we can draw the base of the triangle. Then with a 3th touch we can move along the height and draw the other 2 sides.
//------------------------------------------------------------------ // Triangle //------------------------------------------------------------------ int countTouch =0; float basexTriangle =0; float baseyTriangle =0; private void onDrawTriangle(Canvas canvas){ if (countTouch<3){ canvas.drawLine(mStartX,mStartY,mx,my,mPaint); }else if (countTouch==3){ canvas.drawLine(mx,my,mStartX,mStartY,mPaint); canvas.drawLine(mx,my,basexTriangle,baseyTriangle,mPaint); } } private void onTouchEventTriangle(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: countTouch++; if (countTouch==1){ isDrawing = true; mStartX = mx; mStartY = my; } else if (countTouch==3){ isDrawing = true; } invalidate(); break; case MotionEvent.ACTION_MOVE: invalidate(); break; case MotionEvent.ACTION_UP: countTouch++; isDrawing = false; if (countTouch<3){ basexTriangle=mx; baseyTriangle=my; mCanvas.drawLine(mStartX,mStartY,mx,my,mPaintFinal); } else if (countTouch>=3){ mCanvas.drawLine(mx,my,mStartX,mStartY,mPaintFinal); mCanvas.drawLine(mx,my,basexTriangle,baseyTriangle,mPaintFinal); countTouch =0; } invalidate(); break; } }The next step is to give a kid this example, and he will draw a little home, on the sea with an awesome sun in the sky.
Here you can find a small video to see this code in action.
You can get code from GitHub:
Comments
Post a Comment