Android Graphics - clear canvas while dragging bitmap - java

I've got one bitmap on a canvas (backgroundBitmap) that I want to remain unchanged and another smaller bitmap (draggableBitmap) that I want the user to be able to drag above backgroundBitmap. (And I do mean "above" as in z-axis).
My thinking is that I just redraw the background with each ACTION_MOVE. When I do this with a solid color, it works perfectly. When I redraw the backgroundBitmap instead of the color, the backgroundBitmap remains visible but the draggableBitmap just repeats itself along the dragged path. Why is the solid color working to "clear" the image and a bitmap won't?
EDIT:
Many thanks to Steve K for helping out with this. I've updated the code below to reflect the progress so far. The only issue at this point is that the image goes completely black after dragging begins. Does this have something to do with the background bitmap being set to mutable? I was getting a mutability error without it.
package com.example.drawing;
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.Path;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class DrawingView extends View {
// drawing and canvas paint
private Paint canvasPaint;
// canvas
private Canvas drawCanvas;
// canvas bitmap
private Bitmap backgroundBitmap, draggableBitmap;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
private void setupDrawing() {
canvasPaint = new Paint();
canvasPaint.setColor(Color.TRANSPARENT);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
BitmapFactory.Options opt1 = new BitmapFactory.Options();
opt1.inMutable = true;
opt1.inSampleSize = 4;
BitmapFactory.Options opt2 = new BitmapFactory.Options();
opt2.inMutable = true;
backgroundBitmap = BitmapFactory.decodeFile("/storage/emulated/0/DCIM/Camera/20140901_223343.jpg", opt1);
draggableBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.draggable_image, opt2);
drawCanvas = new Canvas(backgroundBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(backgroundBitmap, 0, 0, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Nothing here
break;
case MotionEvent.ACTION_MOVE:
drawCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
drawCanvas.drawBitmap(backgroundBitmap, 0, 0, null);
drawCanvas.drawBitmap(draggableBitmap, touchX, touchY, null);
break;
case MotionEvent.ACTION_UP:
// Nothing here
break;
default:
return false;
}
invalidate();
return true;
}
}

The color has no defined boundaries, so it 'clears' the canvas by writing to every pixel. Your floating bitmap doesn't - it only redraws in the place where it is. The whole canvas needs to be redrawn, first cleared with a color, then drawn over.
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Nothing here
break;
case MotionEvent.ACTION_MOVE:
drawCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
drawCanvas.drawBitmap(backgroundBitmap, 0, 0, null);
drawCanvas.drawBitmap(draggableBitmap, touchX, touchY, null);
break;
case MotionEvent.ACTION_UP:
// Nothing here
break;
default:
return false;
}
invalidate();
return true;
}

Yes, when you create the canvas, it must have a mutable bitmap to draw into. When you tried to draw backgroundBitmap to the canvas which had been initialized with backgroundBitmap as its target, it drew the backgroundBitmap, but the important thing to understand is that since it's your target drawing surface, what backgroundBitmap contains is literally the picture that you see (the sum total of everything drawn to the canvas), so when you draw it again, nothing happens. By initializing the canvas with backgroundBitmap, everything you drew to the canvas CHANGED backgroundBitmap. You need a clean surface to draw into that's not one of your sprites.

I ended up adding a third bitmap. While I confess I don't entirely understand how this works, I did remember reading something about the necessity of a bitmap to which all other drawings were applied in a Canvas.
drawCanvas is constructed with canvasBitmap and then drawCanvas is used to redraw the bgBitmap and draggableBitmap. I'm assuming my error in the original code was that the canvasBitmap was constructed using the bitmap I was trying to draw over it?
package com.example.drawing;
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.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class DrawingView extends View {
// drawing and canvas paint
private Paint canvasPaint;
// canvas
private Canvas drawCanvas;
// canvas bitmap
private Bitmap canvasBitmap, draggableBitmap, bgBitmap;
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
private void setupDrawing() {
canvasPaint = new Paint();
canvasPaint.setColor(Color.TRANSPARENT);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
BitmapFactory.Options opt1 = new BitmapFactory.Options();
opt1.inMutable = true;
opt1.inSampleSize = 4;
BitmapFactory.Options opt2 = new BitmapFactory.Options();
opt2.inMutable = true;
bgBitmap = BitmapFactory.decodeFile("/storage/emulated/0/DCIM/Camera/20140901_223343.jpg", opt1);
draggableBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.draggable_image, opt2);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
drawCanvas.drawBitmap(bgBitmap, 0, 0, null);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Nothing here
break;
case MotionEvent.ACTION_MOVE:
drawCanvas.drawBitmap(bgBitmap, 0, 0, null);
drawCanvas.drawBitmap(draggableBitmap, touchX, touchY, null);
break;
case MotionEvent.ACTION_UP:
// Nothing here
break;
default:
return false;
}
invalidate();
return true;
}
}

Related

How to make canvas scrollable after scaling in Android Studio(Java)

I am developing an app in which I am showing canvas above pdf file so I can annotate it with free hand drawing to give remarks. My problem is that my canvas is zoomable but not scrollable. I am able to scale the canvas but unable to scroll it. Zoomed area is not scrollable please help how I can achieve it. My code is below
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import com.github.barteksc.pdfviewer.PDFView;
import com.example.smartschool.ViewPDFFileActivity;
public class PaintView extends PDFView {
static Path drawPath;
//drawing and canvas paint
private static Paint drawPaint;
private static Paint canvasPaint;
//initial color
static int paintColor = 0xFFFF0000;
//stroke width
private static float STROKE_WIDTH = 5f;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//eraser mode
private static boolean erase=false;
boolean scaling=false;
private float scaleFactor = 1.f;
public ScaleGestureDetector detector = new ScaleGestureDetector(getContext(), new ScaleListener());
//constructor
public PaintView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
setErase(erase);
}
private static void setupDrawing(){
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(STROKE_WIDTH);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//*************************************** View assigned size ****************************************************
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
public static void setErase(boolean isErase){
erase=isErase;
drawPaint = new Paint();
if(erase) {
setupDrawing();
int srcColor= 0x00000000;
PorterDuff.Mode mode = PorterDuff.Mode.CLEAR;
PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(srcColor, mode);
drawPaint.setStrokeWidth(40);
drawPaint.setColorFilter(porterDuffColorFilter);
drawPaint.setColor(srcColor);
drawPaint.setXfermode(new PorterDuffXfermode(mode));
}
else {
setupDrawing();
}
}
//************************************ draw view *************************************************************
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawCanvas.drawColor(Color.TRANSPARENT);
canvas.save();
canvas.scale(scaleFactor, scaleFactor);
canvas.drawPath(drawPath, drawPaint);
canvas.drawBitmap(canvasBitmap,0,0, canvasPaint);
canvas.restore();
}
//*************************** respond to touch interaction **************************************************
#Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);
float touchX = event.getX()/scaleFactor;
float touchY = event.getY()/scaleFactor;
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(ViewPDFFileActivity.isDrawEnabled)
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
if(ViewPDFFileActivity.isDrawEnabled) {
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.lineTo(touchX, touchY);
}
break;
case MotionEvent.ACTION_UP:
if(ViewPDFFileActivity.isDrawEnabled) {
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
}
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
//*********************************** return current alpha ***********************************************
public int getPaintAlpha(){
return Math.round((float)STROKE_WIDTH/255*100);
}
//************************************** set alpha ******************************************************
public void setPaintAlpha(int newAlpha){
STROKE_WIDTH=Math.round((float)newAlpha/100*255);
drawPaint.setStrokeWidth(newAlpha);
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
if(ViewPDFFileActivity.isDrawEnabled) return true;
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(1f, Math.min(scaleFactor, 5f));
invalidate();
ViewPDFFileActivity.pdfView.setMaxZoom(scaleFactor);
ViewPDFFileActivity.pdfView.zoomTo(scaleFactor);
ViewPDFFileActivity.pdfView.invalidate();
return true;
}
#Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
scaling=true;
return super.onScaleBegin(detector);
}
#Override
public void onScaleEnd(ScaleGestureDetector detector) {
super.onScaleEnd(detector);
scaling=false;
}
}
}

I cant draw on my Canvas by onTouch method.Why dont work?

This is my first question here! I hope that you can help me!
I'm explain:
I'm trying to develop an app like a paint in android studio to work with Paint,Canvas,and this class...
I have a class call Lienzo.java; This is the code of my class:
package com.example.pedro.paint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.graphics.Path;
/**
* Created by Pedro on 26/02/2018.
*/
public class Lienzo extends View {
//PATH TO DRAW THE LINES
private Path drawPath;
//PAINT DRAWING AND PAINT CANVAS
private Paint drawPaint,canvasPaint;
//COLOR INITIAL
private int paintColor=0xFFFF0000;
//CANVAS
private Canvas drawCanvas;
//CANVAS TO SAVE
private Bitmap canvasBitmap;
public Lienzo(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
private void setupDrawing(){
//CONFIGURATION AREA TO DRAW
drawPath = new Path();
drawPaint=new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(20);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint= new Paint(Paint.DITHER_FLAG);
}
//ASIGN SIZE TO VIEW
#Override
protected void onSizeChanged(int w, int h,int oldw, int oldh){
super.onSizeChanged(w,h,oldw,oldh);
canvasBitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
drawCanvas=new Canvas(canvasBitmap);
}
//PAINT THE VIEW.CALL BY ONTHOUCHEVENT
#Override
protected void onDraw(Canvas canvas){
canvas.drawBitmap(canvasBitmap,0,0,canvasPaint);
canvas.drawPath(drawPath,drawPaint);
}
//REGISTER USER TOUCH
public boolean OnTouchEvent(MotionEvent event)
{
float touchX =event.getX();
float touchY=event.getY();
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX,touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX,touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX,touchY);
drawCanvas.drawPath(drawPath,drawPaint);
drawPath.reset();
break;
default:
return false;
}
//REPAINT
invalidate();
return true;
}
}
I have no error but I try to paint but do nothing.
This is a copy of an example.The original https://www.youtube.com/watch?v=GAr_agEokr8 works but my code,its equal and dont work.
Anybody knows why?
Thanks and regards!
OnTouchEvent change to onTouchEvent and add #Override

Draw a circle in Android Canvas when previous circle was selected at predefined positions

This is my first time using Canvas in Android.
I am creating an app that would display circles at certain positions on the screen one at a time (positions are selected randomly). New circle should be drawn after the previous one was selected/touched, and the previous one should disappear.
I have some ideas about it: to keep an arraylist of Point objects(each object contains x,y coordinate of the centre of the circle) and randomly select one each time the circle is drawn on the screen. So first I am populating an array of points. I also know how to randomly select the element from arraylist.
My biggest confustion is how to connect onDraw and onTouchEvent methods with each other? I know I should check if the circle was selected and only then draw a new circle at the randomly selected position, but I m not sure how to make a call for onDraw() method from the onTouchEvent...
Could you please help with this issue?
My code is below:
package com.example.researcher.heatmap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* TODO: document your custom view class.
*/
public class MyView extends View {
Paint paint;
ArrayList<Point> points = new ArrayList<>();
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// Load attributes
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
populateArrayList();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
canvas.drawColor(Color.WHITE);
int i=1; // should be random, will randomize later
for(Point p: points) {
p.x = points.get(i).x;
p.y = points.get(i).y;
canvas.drawCircle(p.x, p.y, 50, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int i=1;
for(Point p: points) {
Canvas canvas = new Canvas();
p.x = points.get(i).x;
p.y = points.get(i).y;
canvas.drawCircle(p.x, p.y, 50, paint);
}
postInvalidate();
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
break;
}
}
postInvalidate();
return true;
}
public void populateArrayList(){
points.clear();
points.add(new Point(120, 120));
points.add(new Point(150, 320));
points.add(new Point(280, 200));
}
}
Thank you Chris for your help! I really appreciate it.
Here is my solution if someone will need it for reference
package com.example.researcher.heatmap;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* TODO: document your custom view class.
*/
public class MyView extends View {
Paint paint;
ArrayList<Point> points = new ArrayList<>();
private int pointsPos = 0; //Which point we will be drawing
public float x;
public float y;
public int radius = 150;
public MyView(Context context) {
super(context);
x = this.getX();
y = this.getY();
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
x = this.getX();
y = this.getY();
init();
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
x = this.getX();
y = this.getY();
init();
}
private void init() {
// Load attributes
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
populateArrayList();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
canvas.drawColor(Color.WHITE);
canvas.drawCircle(points.get(pointsPos).x, points.get(pointsPos).y, radius, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
//Check if the point press is within the circle
if(contains(event, points.get(pointsPos))){
Random r = new Random(System.nanoTime());
pointsPos = r.nextInt(points.size());; //between 0 and points.length
postInvalidate();
}
case MotionEvent.ACTION_CANCEL: {
break;
}
}
postInvalidate();
return true;
}
private boolean contains(MotionEvent event, Point point) {
float xTouch = event.getX();
float yTouch = event.getY();
if ((xTouch - point.x) * (xTouch - point.x) + (yTouch - point.y) * (yTouch - point.y) <= radius * radius) {
return true;
}
else {
return false;
}
}
public void populateArrayList(){
points.clear();
points.add(new Point(220, 1020));
points.add(new Point(550, 320));
points.add(new Point(780, 500));
}
}
Class var
private int state = 0 //0 normal, 1 new circle
private int pointPos = 0; //Which point we will be drawing
onDraw was overwriting the x/y of all your other points
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
canvas.drawColor(Color.WHITE);
if(state == 1){
pointPos = random(); //between 0 and points.length
state = 0;
}
canvas.drawCircle(points.get(pointsPos).x, points.get(pointsPos).y, 50, paint);
}
onTouchEvent: Drawing should only be done on the ondraw, use flags/states to keep track of what you should be doing on the next draw call
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Though these days this is usually done on the up event
//Check if the point press is within the circle
if(contains(event, points.get(pointPos))){
state = 1;
postInvalidate();
}
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
break;
}
}
postInvalidate();
return true;
}

Android onTouchEvent in a view class

I've tried debugging with messages and stuff but the only value i get from event.getAction() is 0 ... which i believe is ACTION_DOWN why dont i detect ACTION_MOVE or ACTION_UP??
package com.andrewxd.test01;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
public class Game extends View {
private Bitmap enemy;
private Enemy enemyN;
private Paint paint;
private float x,y;
public Game(Context context) {
super(context);
enemy = BitmapFactory.decodeResource(getResources(), R.drawable.enemy);
enemy = Bitmap.createScaledBitmap(enemy, 300 , 300, false);
enemyN = new Enemy(10, 10, enemy);
paint = new Paint();
x = 0;
y = 0;
}
#Override
protected void onDraw(Canvas canvas){
canvas.drawRect(x, y, 50, 50, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event){
super.onTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_DOWN){
x = event.getX();
y = event.getY();
invalidate();
} else if(event.getAction() == MotionEvent.ACTION_MOVE){
x = event.getX();
y = event.getY();
invalidate();
}
return false;
}
}
Am I doing something wrong? or is this supposed to work like this? And if this is supposed to be like this where do i detect touch movement
It's because you're returning false at the end of the onTouchEvent. When you return false, you are saying that your View can not handle any more touch events so the events will no longer be sent to the View. If you want to receive MOVE and UP events, then you need to return true.

Best way to determine screen dimensions for signature capture stroke width?

What would be the best way to determine screen size in an external class and then adjust the stroke width of a handwriting capture view, so that it scales nicely?
I've got this SignatureCanvas.java class, in an external library. As you can see I've set the stroke width to a constant, which works (nothing strange there!). However, as I've been testing on various devices and emaulators (of differing screen size), the stroke width isn't translated to any kind of under-the-hood pixel->dip (which is understandable!). So, on older/smaller screen sizes, this stroke width of 8, actually looks like it's 14, and the signature becomes unreadable.
I've brainstormed a bit and have come up with the idea of generalising screen resolutions and having a default stroke width for each 'bracket' (so to speak), and applying it as and when I need to. However, that seems a bit rubbish and I was wondering if anyone has had this dilemma previously and how you solved it?
The class is here purely for demonstration purposes, there is nothing wrong with the code per-se.
package com.goosesys.gooselib.Views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class SignatureCanvas extends View {
private final float STROKE_WIDTH = 8f;
private final boolean ANTI_ALIAS = true;
private final int DEFAULT_PEN_COLOUR = 0xFF000000;
private Path drawPath;
private Paint drawPaint;
private Paint canvasPaint;
private int paintColour = DEFAULT_PEN_COLOUR;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
/*
* Constructors
*/
// Main in-code constructor //
public SignatureCanvas(Context context) {
super(context);
setupDrawing();
}
// Constructor for use in UI layout tool - Custom Views
public SignatureCanvas(Context context, AttributeSet attributeSet){
super(context, attributeSet);
setupDrawing();
}
/*
* Methods
*/
private void setupDrawing(){
drawPath = new Path();
drawPaint = new Paint();
// set initial colour for drawing
drawPaint.setColor(paintColour);
// setup paths
drawPaint.setAntiAlias(ANTI_ALIAS);
drawPaint.setStrokeWidth(STROKE_WIDTH);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
// finally create a new canvas paint object
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
public void clearCanvas(){
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
public Bitmap saveSignature(){
return Bitmap.createBitmap(canvasBitmap);
}
/*
* (non-Javadoc)
* #see android.view.View#onSizeChanged(int, int, int, int)
*/
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh){
super.onSizeChanged(w, h, oldw, oldh);
// view given size
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
#Override
protected void onDraw(Canvas canvas){
// draw view
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#Override
public boolean onTouchEvent(MotionEvent event){
// detect user touch
float touchX = event.getX();
float touchY = event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
}
public static int convertDpsToPixels(Context context, int dps) {
// http://developer.android.com/guide/practices/screens_support.html
// Convert the dps to pixels
final float scale = context.getResources().getDisplayMetrics().density;
final float dpsFloat = dps;
return (int) (dpsFloat * scale + 0.5f);
}

Categories