I have already set up the canvas for the drawing. My problem now is how to clear the drawing.
Tried doing this to no avail.
public void clear()
{
circlePath.reset();
mPath.reset();
// Calls the onDraw() method
//invalidate();
}
Please take a look at the whole code here:
https://gist.github.com/akosijiji/a29cca90bead2e5e35ad
Any help is truly appreciated.
On button click
b1.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
dv.clear(); // call clear method using in your custom view
}
});
Define a clear method in your custom view
public void clear()
{
mBitmap = Bitmap.createBitmap(width,height ,
Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
//Added later..
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
invalidate();
}
Reset all drawing tools and call invalidate to refresh the view.
Complete working code
public class MainActivity extends Activity implements ColorPickerDialog.OnColorChangedListener {
DrawingView dv ;
RelativeLayout rl;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(R.layout.activity_main);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
rl = (RelativeLayout) findViewById(R.id.rl);
rl.addView(dv);
Button b = (Button) findViewById(R.id.button1);
//b.setText(R.string.France);
Button b1 = (Button) findViewById(R.id.button2);
rl.setDrawingCacheEnabled(true);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// dv.clear();
new ColorPickerDialog(MainActivity.this, MainActivity.this, mPaint.getColor()).show();
}
});
b1.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
dv.clear();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
public class DrawingView extends View {
private int width;
private int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
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);
width =w;
height =h;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
public void clear()
{
mBitmap = Bitmap.createBitmap(width,height ,
Bitmap.Config.ARGB_8888);
//Log.d("BITMAP","Restoring...");
//mBitmap=BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
//Added later..
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawPath(circlePath, circlePaint);
}
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);
// invalidate();
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
// mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));//.Mode.SCREEN));
mPaint.setMaskFilter(null);
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SCREEN);
}
#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
public void colorChanged(int color) {
// TODO Auto-generated method stub
mPaint.setColor(color);
}
}
The above works but it is not good design coz everytime you need to clear you will be creating objects like paint object.
You can create singleton class and have your tools reset and then call invalidate
public class DrawingManager {
private static DrawingManager mInstance=null;
public DrawingTools mDrawingUtilities=null;
public int mThemeIndex;
public Canvas mCanvas;
public Path mPath;
public Paint mBitmapPaint;
public Bitmap mBitmap;
public Paint mPaint;
private DrawingManager()
{
resetDrawingTools();
}
public static DrawingManager getInstance()
{
if(mInstance==null)
{
mInstance=new DrawingManager();
}
return mInstance;
}
public void resetDrawingTools()
{
mBitmap = Bitmap.createBitmap(screenwidth,screenheight ,
Bitmap.Config.ARGB_8888)
mCanvas = new Canvas(mBitmap);
Path = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
//Added later..
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.Green);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
/**
* Clears the drawing board.
*/
public static void clearDrawingBoard()
{
mInstance=null;
}
public void resetBitmapCanvasAndPath() {
// TODO Auto-generated method stub
mBitmap = Bitmap.createBitmap(screenwidth,screenheight ,
Bitmap.Config.ARGB_8888);
//Log.d("BITMAP","Restoring...");
//mBitmap=BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mCanvas = new Canvas(.mBitmap);
mPath = new Path();
}
}
In your painting class
private DrawingManager mDrawingManager=null;
mDrawingManager=DrawingManager.getInstance();// initialize drawing tools once
Then on button click to clear draw
mDrawingManager.resetBitmapCanvasAndPath();
invalidate();
you should use yourpaintlayout.removeallviews();
you would have added one layout to your drawing canvas class. You will have option to remove all views from your drawing layout. hope this will help you.
Related
I can draw by fingers in canvas, but I can not zoom it by two fingers without loss of scale drawn
and I want to do infinite my canvas size
I have this code:
public class MainActivity1 extends AppCompatActivity {
DrawingView dv ;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
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);
mBitmap = Bitmap.createBitmap(1000, 1000, 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);
canvas.drawPath( circlePath, circlePaint);
}
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, 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;
}
}
}
Please give me advice how to do it?
And I also want to do infinite my canvas size - its optional.
Main problem is zoom
My advice - you can use opengl. It's looks like you want to create some drawer, but canvas not perfect solution for this. Currently almost all devices support opengl es. It faster than canvas and you can made many another function(as scaling, image pasting, 3d objects etc.) much more easier. Here you can find a good tutorial.
Yoo should use ScaleGestureDetector to scale your canvas. This is my sample code:
private class MyScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
return true;
}
public boolean onScaleBegin(ScaleGestureDetector detector) {
Log.d("myZoomTag", "SCALE STARTED");
return true;
}
public void onScaleEnd(ScaleGestureDetector detector) {
Log.d("myZoomTag", "SCALE ENDED");
}
}
Here scaleFactor is global variable. In your onDraw method you should do something like this:
bitmapWidth *= scaleFactor;
bitmapHeight *= scaleFactor;
i have one question,
I've made a project to draw an image. and it worked! but I am confused, I must add a button to check whether someone is really drawing all the parts of the image or not.
This is my code.
MainActivity.java
public class MainActivity extends Activity {
DrawingView dv;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(5);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context = c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
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);
//mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.asd) //-->here load your image
.copy(Bitmap.Config.ARGB_8888, true);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
canvas.drawPath(circlePath, circlePaint);
}
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, 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;
}
}
}
What from the code can be checked drawing?
and I do not know where to make checking function.
can you help me? thank you :)
I'm developing an app that need the feature in object.
I have an Image A that cover an Image B. With finger I need to erase the Image A to show the Image B.
Erase must follow your finger flowing image A
I'm trying some code but still I couldn't erase the image A. this is the code that i'm using to draw a line on image (_imageToErase is Image A):
Canvas canvas;
Paint paint;
float downx = 0, downy = 0, upx = 0, upy = 0;
ImageView _imageToErase;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.g_layout);
_imageToErase = (ImageView) findViewById(R.id.image_to_erase);
_imageToErase.setOnTouchListener(this);
}
#Override
public void onWindowFocusChanged(boolean hasFocus){
int width = _imageToErase.getWidth();
int height = _imageToErase.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStrokeWidth(25);
paint.setAntiAlias(true);
_imageToErase.setImageBitmap(bitmap);
}
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
downx = event.getX();
downy = event.getY();
break;
case MotionEvent.ACTION_MOVE:
upx = event.getX();
upy = event.getY();
canvas.drawLine(downx, downy, upx, upy, paint);
_imageToErase.invalidate();
downx = upx;
downy = upy;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
return true;
}
This code produce only a line that follow the finger but not erase the image.
How to modify this code to erase the image? Thanks
EDIT
The link suggested in comments not solved my problem. Simply add this line:
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
not work for me.
PaintView.java
public class PaintView extends View implements View.OnTouchListener {
private static final String TAG = "PaintView";
Bitmap Bitmap1, Bitmap2;
Bitmap Transparent;
int X = -100;
int Y = -100;
Canvas c2;
private boolean isTouched = false;
Paint paint = new Paint();
Path drawPath = new Path();
public PaintView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int width = metrics.widthPixels;
int height = metrics.heightPixels;
Transparent = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.cake1);
Bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.cake2);
c2 = new Canvas();
c2.setBitmap(Transparent);
c2.drawBitmap(Bitmap2, 0, 0, paint);
paint.setAlpha(0);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setAntiAlias(true);
}
private static Point getDisplaySize(final Display display) {
final Point point = new Point();
point.x = display.getWidth();
point.y = display.getHeight();
return point;
}
#Override
protected void onDraw(Canvas canvas) {
System.out.println("onDraw");
if(isTouched)
{
canvas.drawBitmap(Bitmap1, 0, 0, null);
}
canvas.drawBitmap(Transparent, 0, 0, null);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
isTouched = true;
X = (int) event.getX();
Y = (int) event.getY();
paint.setStrokeWidth(60);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(X, Y);
c2.drawPath(drawPath, paint);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(X, Y);
c2.drawPath(drawPath, paint);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(X, Y);
c2.drawPath(drawPath, paint);
drawPath.reset();
count=0;
break;
default:
return false;
}
invalidate();
return true;}}class Point {
float x, y;
#Override
public String toString() {
return x + ", " + y;
}}
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new PaintView(this));
}}
Finally I found a library that works very well for me and implementation is pretty simple
https://github.com/winsontan520/Android-WScratchView
Import library in your project and then in layout.xml
<com.winsontan520.WScratchView
android:layout_width="287dp"
android:layout_height="212dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="80dp"
android:adjustViewBounds="true"
android:scaleType="centerInside"
android:id="#+id/image_to_erase"/>
in onCreate:
_imageToErase = (WScratchView) findViewById(R.id.image_to_erase);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img_erase);
_imageToErase.setScratchBitmap(bitmap);
_imageToErase.setOnScratchCallback(new WScratchView.OnScratchCallback() {
#Override
public void onScratch(float percentage) {
updatePercentage(percentage);
}
#Override
public void onDetach(boolean fingerDetach) {
if (mPercentage > 40) {
_imageToErase.setScratchAll(true);
updatePercentage(100);
}
}
});
and
private void updatePercentage(float percentage) {
mPercentage = percentage;
// System.out.println("percentage = "+percentage);
}
Thanks everybody
I'm searching how I can change style of pen. I would like to get something like array of pixels. Not a stroke. When user will touch the screen, on the canvas appear a black square.
My code:
public class DrawingView extends View {
private Bitmap cacheBitmap;
private Canvas cacheCanvas;
private Paint paint;
private Paint BitmapPaint;
private Path path;
private int height;
private int width;
/** Last saved X-coordinate */
private float pX;
/** Last saved Y-coordinate*/
private float pY;
private int counterxy=0;
/** Initial color */
private int paintColor = Color.BLACK;
private static Paint.Style paintStyle = Paint.Style.STROKE;
/** Paint Point size */
private static int paintWidth = 8;
private Canvas canvas;
private DrawingViewInterface mInterface;
/** get the height and width */
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
height = h;
width = w;
init();
}
public void setViewListener(DrawingViewInterface interface1) {
mInterface = interface1;
}
private void init(){
cacheBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
cacheCanvas = new Canvas(cacheBitmap);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
path = new Path();
BitmapPaint = new Paint();
updatePaint();
}
private void updatePaint(){
paint.setColor(paintColor);
paint.setStyle(paintStyle);
paint.setStrokeWidth(paintWidth);
}
public DrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawingView(Context context){
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
path.moveTo(event.getX(), event.getY());
pX = event.getX();
pY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
path.quadTo(pX, pY, event.getX(), event.getY());
pX = event.getX();
pY = event.getY();
counterxy++;
mInterface.onActionFinished(pX, pY, counterxy); // Wyslanie wspolrzednych do MainActivity
break;
case MotionEvent.ACTION_UP:
cacheCanvas.drawPath(path, paint);
path.reset();
break;
}
invalidate();
return true;
}
#Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
BitmapPaint = new Paint();
canvas.drawBitmap(cacheBitmap, 0,0, BitmapPaint);
canvas.drawPath(path, paint);
}
}
Paint.setStrokeWidth may be enough if all you want is a rectangle. Otherwise you may want setPathEffect(), although for something complex you may need to create your own PathEffect.
I want to erase my bitmap but I don't want to erase background image. When I try to erase is white and it draw very hard in frames.
This is from CanvasView
erasePaint.setColor(Color.WHITE);
//erasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
erasePaint.setAntiAlias(true);
erasePaint.setStyle(Paint.Style.STROKE);
erasePaint.setStrokeJoin(Paint.Join.ROUND);
erasePaint.setStrokeWidth(12);
//....
protected void onDraw(Canvas canvas) {
paint.setPathEffect(null);
if(bitmap!=null){
for(MyEraser e:eraserList){
canvas.drawPath(e.p,erasePaint);
invalidate();
}
final OnTouchListener eraseListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
// erasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//FirstActivity.ll.setVisibility(LinearLayout.GONE);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
myEraser = new MyEraser();
lastTouchX = event.getX();
lastTouchY = event.getY();
myEraser.mouseDown(event.getX(), event.getY());
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
resetDirtyRect(event.getX(),event.getY());
int historySize = event.getHistorySize();
for(int i=0;i<historySize;i++){
float historicalX = event.getHistoricalX(i);
float historicalY = event.getHistoricalY(i);
expandDirtyRect(historicalX, historicalY);
myEraser.mouseUp(historicalX, historicalY);
}
myEraser.mouseUp(event.getX(), event.getY());
eraserList.add(myEraser);
break;
default:
Log.d("mock it up", "Unknown touch event " + event.toString());
return false;
}
invalidate(
(int) (dirtyRect.left - HALF_STROKE_WIDTH),
(int) (dirtyRect.top - HALF_STROKE_WIDTH),
(int) (dirtyRect.right + HALF_STROKE_WIDTH),
(int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
lastTouchX = event.getX();
lastTouchY = event.getY();
return true;
}
};
}
}
This is MyEraser
public class MyEraser {
Paint paint = new Paint();
Path p = new Path();
public MyEraser(){
paint.setColor(Color.WHITE);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(5);
}
public void mouseDown(float x, float y) {
//path.addCircle(x,y,5,Path.Direction.CW);
p.moveTo( x, y );
// path.lineTo(x, y);
}
public void mouseMove(Path path, float x, float y) {
// path.addCircle(x,y,5,Path.Direction.CW);
}
public void mouseUp(float x, float y){
//path.addCircle(x,y,5,Path.Direction.CW);
p.lineTo(x, y);
}
public void draw(Canvas c,Path path){
//paint.setColor(Color.WHITE);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(7);
c.drawPath(p, paint);
}
}
EDIT: Started over for better explanation :)
I am not familiar with Android, in fact I have never used it. Use this code as an example of how to organize your code, rather than a functional code.
class MyView extends View {
private Eraser myEraser;
private Bitmap myBackgroundImage;
private Canvas myForegroundCanvas;
public MyView(Context context, Attributes, attrs) {
myEraser = new Eraser()
myBackgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.your_background_name);
Bitmap image = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); // the width and height of the view
myForegroundCanvas = new Canvas(image);
}
public boolean onTouchEvent(MotionEvent event) {
// update your eraser path
return true;
}
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(myBackgroundImage, 0, 0, null);
//for (Eraser item : eraserList) {
// if you have multiple eraser, add them to a list
myEraser.draw(myForegroundCanvas);
//}
canvas.drawCanvas(myForegroundCanvas, 0, 0, null);
}
}
The main idea is to keep the separation between your background and foreground images. That way, you could easily change the background and it would be updated. You could also have a reset on the foreground to erase everything, etc.
I hope this helps you.