I'm trying to create a drawing app and found an example from Fingerpaint. I made some modification on the example and was trying to understand how this is accomplished. the example I have is below.
public class TestView extends View {
private Paint mPaint;
private Paint mBitmapPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TestView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public TestView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
mPath = new Path();
mBitmapPaint = new Paint();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(20);
}
#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);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
I understand how mPaint is constructed and used. What I don't understand is the code in onSizeChanged() and this line canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
. why is there a need to new a Canvas? what is the purpose of creating mBitmap? why should we draw the Bitmap? why is setting color to mBitmapPaint doesn't do anything? Basically I don't understand what mBitmap, mCanvas and mBitmapPaint do. but if I commented those out, the example won't work.
Related
Android custom view drawing:
Screenshot:
This can't save the last trace, i want to redraw on a bitmap but the effect is not very good.
Screenshot:
code:
public class CustomView extends View {
private float sX, sY, eX, eY;
private Paint paint = new Paint();
private Canvas canvas = new Canvas();
private Bitmap bitmap;
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
setBackgroundColor(Color.WHITE);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
eX = event.getX();
eY = event.getY();
canvas.drawLine(sX, sY, eX, eY, paint);
break;
case MotionEvent.ACTION_DOWN:
sX = event.getX();
sY = event.getY();
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, getMatrix(), null);
}
}
Have you ever encountered the same problem?
You should update the sX sY variable, when your finger is moving
ACTION_DOWN point is [100, 100] sX = 100, sY = 100
ACTION_MOVE now finger is locating at [130, 150] eY = 130, eY = 150
invalidate() so will trigger draw() draw line [100, 100] to [130, 150]
finger continue to move
ACTION_MOVE now the start is [130, 150] sX = 130, sY = 150 not ACTION_DOWN point value
ACTION_MOVE now finger is locating at [160, 180]
invalidate() so will trigger draw() draw line [130, 150] to [160, 180]
continue do the same thing .....
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
eX = event.getX();
eY = event.getY();
invalidate()
sX = eX;
sY = eY;
break;
case MotionEvent.ACTION_DOWN:
sX = event.getX();
sY = event.getY();
break;
case MotionEvent.ACTION_UP:
canvas.drawLine(sX, sY, eX, eY, paint);
break;
}
//invalidate();
return true;
}
i have not Run the code, but maybe you have understood what i mean.
you should update both startX startY, and endX endY
I have found a solution, but I don't want to solve the problem in this way. My goal is to solve the problem with only the new canvas.
screenshot
public class CustomView extends View {
private float sX, sY, eX, eY;
private Paint paint = new Paint();
private Canvas canvas = new Canvas();
private Bitmap bitmap;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
canvas.setBitmap(bitmap);
setBackgroundColor(Color.WHITE);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
eX = event.getX();
eY = event.getY();
break;
case MotionEvent.ACTION_DOWN:
sX = event.getX();
sY = event.getY();
break;
case MotionEvent.ACTION_UP:
canvas.drawLine(sX, sY, eX, eY, paint);
break;
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, getMatrix(), null);
canvas.drawLine(sX, sY, eX, eY, paint);
}
}
or
public class CustomView extends View {
private Paint paint = new Paint();
private List<Path> cache = new ArrayList<>();
private Path currentPath;
public CustomView(Context context) {
super(context);
init();
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStyle(Paint.Style.STROKE);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (currentPath != null) {
currentPath.eX = event.getX();
currentPath.eY = event.getY();
}
break;
case MotionEvent.ACTION_DOWN:
currentPath = new Path();
currentPath.sX = event.getX();
currentPath.sY = event.getY();
break;
case MotionEvent.ACTION_UP:
if (currentPath != null) {
cache.add(currentPath);
currentPath = null;
}
break;
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Path path : cache) {
canvas.drawLine(path.sX, path.sY, path.eX, path.eY, paint);
}
if (currentPath == null) return;
canvas.drawLine(currentPath.sX, currentPath.sY, currentPath.eX, currentPath.eY, paint);
}
static class Path {
float sX;
float sY;
float eX;
float eY;
}
}
I am hand drawing images on a canvas and then converting them to a bitmap. Then, I am dragging this on screen. That's all fine, What I want is onTouchEvent to draw a rectangle round this image/s but NOT the whole canvas. So I'm wondering if I can measure the drawing width and height and subtract this from canvas width and height but I'm struggling and not sure How can I achieve this? Unless there's a better idea someone can suggest.
private static class DrawingView extends View {
float x = 0f,y = 0f;
float dX,dY;
Paint paint;
public DrawingView(Context context){
super(context);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.id.main);
paint = new Paint();
}
public boolean onTouchEvent(MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
dX = this.getX() - event.getRawX();
dY = this.getY() - event.getRawY();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
this.setX(event.getRawX() + dX);
this.setY(event.getRawY() + dY);
invalidate();
break;
case MotionEvent.ACTION_UP:
invalidate();
break;
}
return true;
}
#Override
public void onDraw(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmap, x, y, paint);
float left = (x + (bitmap.getWidth()/2));
float top = (y + (bitmap.getHeight()/2));
float right = bitmap.getWidth() - left;
float bottom = bitmap.getHeight() - top;
canvas.drawRect(left, top, right, bottom, paint);
}
}//End of inner class
My drawing class
public class DrawView extends View {
private Paint drawPaint, canvasPaint;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private SparseArray<Path> paths;
public DrawView(Context context) {
super(context);
setupDrawing();
}
public DrawView(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setupDrawing();
}
private void setupDrawing() {
paths = new SparseArray<>();
drawPaint = new Paint();
drawPaint.setColor(Color.BLACK);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(9);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
#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);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
for (int i = 0; i < paths.size(); i++) {
canvas.drawPath(paths.valueAt(i), drawPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int index = event.getActionIndex();
int id = event.getPointerId(index);
final Point p = new Point();
Path path;
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
path = new Path();
path.moveTo(event.getX(index), event.getY(index));
paths.put(id, path);
break;
case MotionEvent.ACTION_MOVE:
for (int i=0; i<event.getPointerCount(); i++) {
id = event.getPointerId(i);
path = paths.get(id);
if (path != null) path.lineTo(event.getX(i), event.getY(i));
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
path = paths.get(id);
if (path != null) {
drawCanvas.drawPath(path, drawPaint);
paths.remove(id);
}
setPenEnabled(true);
break;
default:
return false;
}
invalidate();
return true;
}
/**
* change path color here
*/
public void setPathColor(int color) {
drawPaint.setColor(color);
}
//Clear screen
public void clear() {
canvasBitmap.eraseColor(Color.TRANSPARENT);
paths.clear();
invalidate();
System.gc();
}
}//End of Class
Undo and redo functionality NOT working with below code. Below is the my drawing code implementation.
Is there any problem in below code?
public class DrawingArea extends View {
private Path drawPath;
private Paint drawPaint, canvasPaint;
private int paintColor = 0xFF660000;
private Canvas drawCanvas;
private Bitmap canvasBitmap;
private ArrayList paths = new ArrayList();
private ArrayList undonePaths = new ArrayList();
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
// for Undo, Redo
private int historyPointer = 0;
private boolean erase = false;
public DrawingArea(Context context) {
super(context);
setupDrawing();
}
public DrawingArea(Context context, AttributeSet attrs) {
super(context, attrs);
setupDrawing();
}
public void setupDrawing() {
drawPath = new Path();
drawPaint = new Paint();
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);
//paths.add(drawPath);
}
public void setColor(String newColor) {
invalidate();
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
#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);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
private void touch_start(float x, float y) {
drawPath.reset();
drawPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
drawPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
drawPath.lineTo(mX, mY);
// commit the path to our offscreen
drawCanvas.drawPath(drawPath, drawPaint);
// kill this so we don't double draw
drawPath = new Path();
paths.add(drawPath);
}
public void setErase() {
canvasBitmap.eraseColor(Color.TRANSPARENT);
drawPath.reset();
invalidate();
}
public void startNew() {
drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
invalidate();
}
public void undo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
}
}
public void redo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
}
}
}
Change your OnDraw() like this
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, canvasPaint);
canvas.drawPath(mPath,drawPaint);
for (Path p : paths) {
canvas.drawPath(p, drawPaint);
}
}
and don't forget to add type of data hold by paths arraylist
ArrayList<Path> paths = new ArrayList<Path>();
I am working on android paint signature application where it has the flexibility to clear the paint and save the canvas as bitmap image. I am facing an issue in this app, whenever i want to save the canvas as bitmap i need to check whether the signature is lengthy enough or not.
If the signature is too short them i have to ask the user to put a signature again. The following is my code:
There are two classes in this.
FingerPaintActivity
public class FingerPaintActivity extends Activity implements OnClickListener{
private Button clearBtn, saveBtn;
private View myView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myView = findViewById(R.id.myView);
clearBtn = (Button) findViewById(R.id.clearBtn);
clearBtn.setOnClickListener(this);
saveBtn = (Button) findViewById(R.id.submitBtn);
saveBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v == clearBtn) {
MyView.clearCanvas();
myView.invalidate();
myView.refreshDrawableState();
} else {
myView.setDrawingCacheEnabled(true);
myView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
myView.layout(0, 0, myView.getWidth(), myView.getHeight());
myView.buildDrawingCache(true);
Bitmap bm = Bitmap.createBitmap(myView.getDrawingCache());
myView.setDrawingCacheEnabled(false);
if (bm != null) {
try {
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, "screentest.jpg");
fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
fOut.flush();
fOut.close();
Log.e("ImagePath", "Image Path : " + MediaStore.Images.Media.insertImage( getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName()));
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
This is the second class:
MyView
public class MyView extends View {
// private static final float MINP = 0.25f;
// private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private static Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyView(Context c) {
super(c);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public static void clearCanvas() {
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mCanvas.drawPaint(paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
}
}
The only problem i am facing is while saving the signature i have to check the size of bitmap or canvas or paint before saving it. i don't know which one to check for
If anyone has idea please help me out.
A simple approach would be to sum up the distances between touch coordinates, and only accept the signature if the sum is greater than a certain threshold.
So, keep a running sum of the total distance drawn in touch_move()
mTotal += Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
then later on
if(mTotal >= MINIMUM_SIGNATURE_LENGTH)
{
acceptSignature();
}
I have an activity which has an ImageView in it. What I want to do is be able to draw where the user touches that Imageview with an image from the drawable folder. I've read that the best way is to use Canvas, but I'm not sure where and how I integrate the onDraw method with the onTouchListener. This is what I have so far:
public class Main extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView textView = (TextView)findViewById(R.id.textView);
final ImageView image = (ImageView) findViewById(R.id.imageView2);
//Bitmap
Bitmap viewBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(viewBitmap);
image.draw(canvas);
image.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
textView.setText("Touch coordinates : " + String.valueOf(event.getX()) + "x" + String.valueOf(event.getY()));
return false;
}
});
}
}
So what I want to do is when the user touches the ImageView, an image will be drawn exactly where he touched it.
You're going to want to subclass ImageView in order to override its onDraw() method. By doing so, you can also to the custom touch handling in onTouchEvent() instead of attaching a listener. This is not a complete example, but something like the following:
public class CustomImageView extends ImageView {
private ArrayList<Point) mTouches;
private Bitmap mMarker;
//Java constructor
public CustomImageView(Context context) {
super(context);
init();
}
//XML constructor
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mTouches = new ArrayList<Point>();
mMarker = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_marker_image);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//Capture a reference to each touch for drawing
if(event.getAction() == MotionEvent.ACTION_DOWN) {
mTouches.add( new Point(event.getX(), event.getY()) );
return true;
}
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas c) {
//Let the image be drawn first
super.onDraw(c);
//Draw your custom points here
Paint paint = new Paint();
for(Point p : mTouches) {
c.drawBitmap(mMarker, p.x, p.y, paint);
}
}
}
HTH!
I edited your class like this and it works for me
public class MyImageView extends androidx.appcompat.widget.AppCompatImageView {
private Bitmap mMarker;
private Path mPath, circlePath ;
private Paint paint, circlePaint;
private Canvas mCanvas;
//Java constructor
public MyImageView(Context context) {
super(context);
init();
}
//XML constructor
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mTouches = new ArrayList<Point>();
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(12);
mPath = new Path();
Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mMarker = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mMarker);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, paint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
#Override
protected void onDraw(Canvas c) {
//Let the image be drawn first
super.onDraw(c);
c.drawBitmap(mMarker, 0, 0, paint);
c.drawPath( mPath, paint);
c.drawPath( circlePath, circlePaint);
}
}