I want to implement eraser in my paint app. But the code
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
draws black line on canvas. If I am changing the background color the canvas draws black on it too.
I have also tried using setLayerType() but it draws white on any color background.
// In constructor
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Below is the code for my PaintView.
public class PaintView extends View {
private Bitmap bitmapBackground,bitmapView;
private int backgroundColor;
private int brushSize;
private int eraserSize;
private float mX,mY;
private Canvas canvas=null;
private final int TOUCH_TOLERANCE=4;
private int paintColor;
private int modeStatus;
/*
1 for brush
2 for eraser
*/
private ArrayList<Paint> paints = new ArrayList<>();
private ArrayList<Path> paths = new ArrayList<>();
private int historyPointer=0;
public PaintView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
initialise();
}
private void initialise() {
eraserSize=12;
brushSize=12;
backgroundColor= Color.WHITE;
paintColor = Color.BLACK;
modeStatus = 1;
paints.add(createPaint());
paths.add(new Path());
historyPointer++;
}
private float toPx(int brushSize) {
return brushSize*(getResources().getDisplayMetrics().density);
}
public void init(int width,int height) {
bitmapBackground=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
bitmapView=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
canvas=new Canvas(bitmapView);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(backgroundColor);
canvas.drawBitmap(bitmapBackground,0,0,null);
for (int i=0;i<historyPointer;i++) {
Path path = paths.get(i);
Paint paint = paints.get(i);
canvas.drawPath(path,paint);
}
}
private Paint createPaint() {
Paint paint = new Paint();
paint.setColor(paintColor);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
if (modeStatus==1) {
paint.setXfermode(null);
paint.setShader(null);
paint.setMaskFilter(null);
paint.setStrokeWidth(toPx(brushSize));
}
else {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
paint.setStrokeWidth(toPx(eraserSize));
}
return paint;
}
private Path createPath(float x,float y) {
Path path = new Path();
path.moveTo(x,y);
return path;
}
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor=backgroundColor;
invalidate(); //Redraw
}
public void setBrushSize(int brushSize) {
this.brushSize=brushSize;
modeStatus=1;
}
public void setBrushColor(int color) {
paintColor=color;
}
public void setEraserSize(int eraserSize) {
this.eraserSize=eraserSize;
modeStatus=2;
}
public int getBrushSize() {
return this.brushSize;
}
public int getEraserSize() {
return this.eraserSize;
}
private void updateHistory(Path path) {
if (historyPointer==paths.size()) {
paths.add(path);
paints.add(createPaint());
historyPointer++;
}
else {
// For undo and redo
paths.set(historyPointer,path);
paints.set(historyPointer,createPaint());
historyPointer++;
for (int i=historyPointer,size=paths.size();i<size;i++) {
paths.remove(historyPointer);
paints.remove(historyPointer);
}
}
}
private Path getCurrentPath() {
return paths.get(historyPointer-1);
}
private Paint getCurrentPaint() {
return paints.get(historyPointer-1);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
// Case when finger touches the screen
case MotionEvent.ACTION_DOWN:
touchStart(x,y);
break;
// Case when finger moves on screen
case MotionEvent.ACTION_MOVE:
touchMove(x,y);
break;
// Case when finger is taken away from screen
case MotionEvent.ACTION_UP:
touchUp();
break;
default :
return false;
}
return true;
}
private void touchStart(float x, float y) {
mX=x;
mY=y;
updateHistory(createPath(x,y));
}
private void touchMove(float x, float y) {
float dx = Math.abs(x-mX);
float dy = Math.abs(y-mY);
Path path = getCurrentPath();
if (dx>=TOUCH_TOLERANCE || dy>=TOUCH_TOLERANCE) {
path.quadTo(x,y,(x+mX)/2,(y+mY)/2);
mX=x;
mY=y;
}
invalidate();;
}
private void touchUp() {
}
}
I got the answer after many research and the following worked.
Just save the canvas layer after setting the background color and at last restore to count.
The onDraw method is as follows -
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(backgroundColor);
canvas.drawBitmap(bitmapBackground,0,0,null);
int layerId = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null, Canvas.ALL_SAVE_FLAG); // Line 1 added
for (int i=0;i<historyPointer;i++) {
Path path = paths.get(i);
Paint paint = paints.get(i);
canvas.drawPath(path,paint);
}
canvas.restoreToCount(layerId); // Line 2 added
}
Related
I am trying to use the method mCanvas.drawBitmap(iconBitmap,x-100,y-100, mBitmapPaint); on my MotionEvent.ACTION_DOWN event in my custom view class. However, the image I want to show does not appear on the canvas at that point. I am trying to make a paint application where users can draw free hand and insert images at the same time to play with them.
This is my custom view class:
package com.example.shazs.autismate;
public class PaintView extends View {
public static int BRUSH_SIZE = 20;
public static final int DEFAULT_COLOR = Color.RED;
public static final int DEFAULT_BG_COLOR = Color.WHITE;
private static final float TOUCH_TOLERANCE = 4;
private float mX, mY;
private Path mPath;
private Paint mPaint;
private ArrayList<FingerPath> paths = new ArrayList<>();
private int currentColor;
private int backgroundColor = DEFAULT_BG_COLOR;
private int strokeWidth;
private boolean emboss;
private boolean blur;
private MaskFilter mEmboss;
private MaskFilter mBlur;
private Bitmap mBitmap;
private Paint mBitmapPaint;
private Canvas mCanvas;
private Bitmap iconBitmap;
private static AtomicBoolean drawIcon = new AtomicBoolean();
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(DEFAULT_COLOR);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setXfermode(null);
mPaint.setAlpha(0xff);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mEmboss = new EmbossMaskFilter(new float[] {1, 1, 1}, 0.4f, 6, 3.5f);
mBlur = new BlurMaskFilter(5, BlurMaskFilter.Blur.NORMAL);
}
public void init(DisplayMetrics metrics) {
int height = metrics.heightPixels;
int width = metrics.widthPixels;
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
currentColor = DEFAULT_COLOR;
strokeWidth = BRUSH_SIZE;
}
public void normal() {
emboss = false;
blur = false;
}
public void emboss() {
emboss = true;
blur = false;
}
public void blur() {
emboss = false;
blur = true;
}
public void setPaintColor(int color){
if (currentColor!=color)
Log.d("xyzn","current color changed");
else
Log.d("xyzn","current color not changed");
currentColor=color;
}
public void drawBitmap(Bitmap bm){
drawIcon.set(true);
iconBitmap = bm;
}
public int getPaintColor(){
return currentColor;
}
public void clear() {
backgroundColor = DEFAULT_BG_COLOR;
paths.clear();
normal();
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.save();
mCanvas.drawColor(backgroundColor);
for (FingerPath fp : paths) {
mPaint.setColor(fp.color);
mPaint.setStrokeWidth(fp.strokeWidth);
mPaint.setMaskFilter(null);
if (fp.emboss)
mPaint.setMaskFilter(mEmboss);
else if (fp.blur)
mPaint.setMaskFilter(mBlur);
mCanvas.drawPath(fp.path, mPaint);
}
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y) {
mPath = new Path();
FingerPath fp = new FingerPath(currentColor, emboss, blur, strokeWidth, mPath);
paths.add(fp);
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(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 touchUp() {
mPath.lineTo(mX, mY);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN :
if (drawIcon.get()){
mCanvas.drawBitmap(iconBitmap,x-100,y-100, mBitmapPaint);
mCanvas.save();
break;
}
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE :
if (drawIcon.get())
break;
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP :
if (drawIcon.get()){
drawIcon.set(false);
break;
}
touchUp();
invalidate();
break;
}
return true;
}
}
Main Activity which uses this custom view class and passes the bitmap of object to draw:
public class drawActivity extends AppCompatActivity implements
ColorPickerDialog.OnColorChangedListener {
private PaintView paintView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.css_layout);
paintView = (PaintView) findViewById(R.id.paintView);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
paintView.init(metrics);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.draw:
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.apple);
paintView.drawBitmap(bm);
break;
I use drawIcon to see if the user needs to insert icon or just draw freehand.
Interestingly, when I go into application view of my phone to view all currently running applications, the icon/image shows on the canvas. However when I return to the application, it dissappears. It only happens once after I insert the icon, not repeatedly.
OK, I had to remove the line
mCanvas.drawColor(backgroundColor);
from my onDraw(Canvas canvas) method and call invalidate()
I am beginner in Android and I have a rather simple question. I have created a custom view and then injected it into another layout through xml. I want to make the background of this custom view transparent.
xml injection of my custom view:
<com.sagar.utils.ConnectDotsView
android:id="#+id/connect_dots_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Here is the code of the custom View:
public class ConnectDotsView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private static final int TOUCH_TOLERANCE_DP = 24;
private static final int BACKGROUND = 0xFFDDDDDD;
// Points to be connected.
private List<Point> mPoints = new ArrayList<>();
private int mLastPointIndex = 0;
private int mTouchTolerance;
private boolean isPathStarted = false;
CompleteListener completeListener;
public ConnectDotsView(Context context) {
super(context);
mCanvas = new Canvas();
mPath = new Path();
initPaint();
}
public interface CompleteListener {
void onCompleteListener();
}
public void setOnCompleteListener(CompleteListener listener) {
completeListener = listener;
}
public ConnectDotsView(Context context, AttributeSet attrs) {
super(context, attrs);
mCanvas = new Canvas();
mPath = new Path();
initPaint();
}
public ConnectDotsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mCanvas = new Canvas();
mPath = new Path();
initPaint();
}
public void clear() {
mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mBitmap.eraseColor(BACKGROUND);
mCanvas.setBitmap(mBitmap);
invalidate();
}
#Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
clear();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(BACKGROUND);
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawPath(mPath, mPaint);
mPaint.setColor(Color.parseColor("#56CBF9"));
// TODO remove if you don't want points to be visible.
for (Point point : mPoints) {
canvas.drawPoint(point.x, point.y, mPaint);
mPaint.setColor(Color.BLACK);
}
}
#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(x, y);
invalidate();
break;
}
return true;
}
private void touch_start(float x, float y) {
if (checkPoint(x, y, mLastPointIndex)) {
mPath.reset();
// User starts from given point so path can be drawn.
isPathStarted = true;
} else {
// User starts move from point which does not belong to mPoints list
isPathStarted = false;
}
}
private void touch_move(float x, float y) {
if (isPathStarted) {
mPath.reset();
Point point = mPoints.get(mLastPointIndex);
mPath.moveTo(point.x, point.y);
if (checkPoint(x, y, mLastPointIndex + 1)) {
point = mPoints.get(mLastPointIndex + 1);
mPath.lineTo(point.x, point.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
++mLastPointIndex;
} else {
int positionIndex = mLastPointIndex + 1;
if (positionIndex >= mPoints.size()) {
completeListener.onCompleteListener();
} else {
mPath.lineTo(x, y);
}
}
}
}
private void touch_up(float x, float y) {
mPath.reset();
if (checkPoint(x, y, mLastPointIndex + 1) && isPathStarted) {
// Move finished at valid point so I draw whole line.
// That's the start point of current line segment.
Point point = mPoints.get(mLastPointIndex);
mPath.moveTo(point.x, point.y);
// And that's the end point.
point = mPoints.get(mLastPointIndex + 1);
mPath.lineTo(point.x, point.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
// Increment point index.
++mLastPointIndex;
isPathStarted = false;
}
}
/**
* Checks if user touch point with some tolerance
*/
private boolean checkPoint(float x, float y, int pointIndex) {
if (pointIndex >= mPoints.size()) {
// All dots already connected.
return false;
}
Point point = mPoints.get(pointIndex);
if (x > (point.x - mTouchTolerance) && x < (point.x + mTouchTolerance)) {
if (y > (point.y - mTouchTolerance) && y < (point.y + mTouchTolerance)) {
return true;
}
}
return false;
}
/**
* Sets up paint attributes.
*/
private void initPaint() {
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(12);
mTouchTolerance = dp2px(TOUCH_TOLERANCE_DP);
}
/**
* Converts dpi units to px
*
* #param dp
* #return
*/
private int dp2px(int dp) {
Resources r = getContext().getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
return (int) px;
}
public void setPaint(Paint paint) {
this.mPaint = paint;
}
public Bitmap getBitmap() {
return mBitmap;
}
public List<Point> getPoints() {
return mPoints;
}
public void setPoints(List<Point> points) {
mLastPointIndex = 0;
this.mPoints = points;
}
}
I want to make the above custom View's background as transparent. How can I achieve that either through xml or code?
Thanks in advance.
In your Class ConnectDotsView change:
private static final int BACKGROUND = 0xFFDDDDDD;
to
private static final int BACKGROUND = Color.TRANSPARENT;
or
private static final int BACKGROUND = Color.parseColor("#00000000");
#00AABBCC = ARGB (00 is Alpha, AA is red, BB is green and CC is blue), 00 alpha is 0% and FF is 100%. This mean #00AABBCC will be transparent, #80AABBCC will be at 50% transparent and #FFAABBCC not transparent
Change alpha of your parent view using view.setAlpha(float opacity) where 0f is fully transparent view.
In your initPaint() method, call the following function:
setBackgroundColor(R.color.colorTransparent);
And in the values/colors.xml folder, set your colorTransparent with RGBA as 00:
<color name="colorTransparent">#00000000</color>
Alternatively, when you call your custom view in xml, use: android:background="#00000000".
This should solve your problem.
Edited:
just use setBackgroundColor(Color.TRANSPARENT);
Or setBackgroundColor(0x00000000);
50% opacity: setBackgroundColor(0x80000000);
To control the extent of transparency, use #Robillo's code, but modify this:
<color name="colorTransparent">#xy000000</color>
replace xy with your desired opacity. 00 will be 0% opaque, FF is 100% opaque (ie white colour)
I'm trying to implement a erase function on the Fingerpaint App in the Api Demo's in Android. I change some code based on my needs. At first the erase function works well. I used:
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
It works well when the path has been drawn in the bitmap. But when I implement the Undo and Redo function(the way I achieve it is by using two arraylist and save the path there), PorterDuffXfermode doesn't work. Please take a look at this:
At image 1 I draw some paths(stored in an arraylist. Not drawn in the bitmap canvas)
Then at 2 thats the time I pressed the erase icon. I dont know what causing all the paths to became black. Then at 3 I tried to erase the paths I made(PorterDuffXFermode some says its black). Then when I switch back to drawing mode. It seems that instead or erasing, all it did was draw another path.
Any solutions for this? or workarounds?
Here is the code when to my drawingClass:
//this is where the drawing takes place
public class DrawingClass extends View{
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFF660000;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
private float brushSize,lastBrushSize;
private boolean erase = false;
//array list for paths
private ArrayList<PathPoints> paths = new ArrayList<PathPoints>();
private ArrayList<PathPoints> undonePaths = new ArrayList<PathPoints>();
public Context context;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
public DrawingClass(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
setupDrawing();
}
private void setupDrawing(){
setFocusable(true);
setFocusableInTouchMode(true);
//instantiate the variable to get the last brush size
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
//get drawing area setup for interaction
drawCanvas = new Canvas();
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
//initial properties
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(brushSize);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
//paths.add(new PathPoints(drawPath, paintColor, brushSize));
}
public void setBrushSize(float newSize){
//update brush size
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
newSize, getResources().getDisplayMetrics());
brushSize = pixelAmount;
drawPaint.setStrokeWidth(brushSize);
invalidate();
}
public void setLastBrushSize(float lastSize){
//set the last brush size
lastBrushSize = lastSize;
invalidate();
}
public float getLastBrushSize(){
//return the last brush size
return lastBrushSize;
}
public void setErase(boolean isErase){
//set erase true or false
erase = isErase;
if (erase) {
//drawPaint.setColor(Color.WHITE);
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
else drawPaint.setXfermode(null);
}
public void startNew(){
//creates a new canvass
drawCanvas.drawColor(0,PorterDuff.Mode.CLEAR);
drawCanvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
setDrawingCacheEnabled(true);
String imgSaved = MediaStore.Images.Media.insertImage(
context.getContentResolver(), getDrawingCache(),
UUID.randomUUID().toString()+".png", "drawing");
destroyDrawingCache();
paths.clear();
undonePaths.clear();
invalidate();
}
#Override
protected void onSizeChanged(int w,int h,int oldw,int oldh){
//view given size
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){
//draw view
//save the strokes in the bitmap
//canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
for (PathPoints p : paths){
drawPaint.setColor(p.getColor());
drawPaint.setStrokeWidth(p.getBrush());
invalidate();
canvas.drawPath(p.getPath(), drawPaint);
}
}
private void touch_start(float x, float y){
drawPath.reset();
drawPath.moveTo(x, (float) (y+.1));
drawPath.lineTo(x, y);
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);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath = new Path();
paths.add(new PathPoints(drawPath, paintColor, brushSize));
}
#Override
public boolean onTouchEvent(MotionEvent event){
//detect user touch
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
invalidate();
touch_start(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
invalidate();
touch_move(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
invalidate();
touch_up();
drawPath.reset();
break;
default:
return false;
}
invalidate();
return true;
}
public void undoPath(){
if (paths.size()>0) {
undonePaths.add(paths.remove(paths.size()-1));
} else {
Log.d("Undo", "No paths left");
}
invalidate();
}
public void redoPath(){
if (undonePaths.size()>0) {
paths.add(undonePaths.remove(undonePaths.size()-1));
} else {
Log.d("Redo", "No paths left");
}
invalidate();
}
public void setColor(String newColor){
//set color
paintColor = Color.parseColor(newColor);
drawPaint.setColor(paintColor);
invalidate();
}
class PathPoints{
private Path path;
private int color;
private float brushsize;
private int x, y;
//holds the paths data
public PathPoints(Path path, int color, float brushsize) {
this.path = path;
this.color = color;
this.brushsize = brushsize;
}
public Path getPath() {
return path;
}
public void setPath(Path path) {
this.path = path;
}
public float getBrush(){
return brushsize;
}
public void setBrush(float brushsize){
this.brushsize = brushsize;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
}
I'm using this app to draw free lines in android
DrawerView.java
public class DrawerView extends View {
public static Paint paint;
Paint paint2 = new Paint();
public Path path = new Path();
public Path circlePath = new Path();
public static int lineCol = Color.BLUE;
public static boolean isTouchable = false;
public LayoutParams params;
public DrawerView(Context context, AttributeSet attrs){
super(context, attrs);
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(lineCol);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(4f);
}
public void onButtonPress(){
// resets the screen
path.reset();
// Calls the onDraw() method
postInvalidate();
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isTouchable){
return false;
} else {
// Gives you x and y coordinates on the Event.
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(pointX, pointY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(pointX, pointY);
circlePath.reset();
circlePath.addCircle(pointX, pointY, 30, Path.Direction.CW);
break;
case MotionEvent.ACTION_UP:
circlePath.reset();
break;
default:
return false;
}
postInvalidate();
return true;
}
}
}
DrawLines.java
public class DrawLines extends Activity {
DrawerView myView;
public Button btnReset;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.draw_line);
myView = (DrawerView)findViewById(R.id.custView);
btnReset = (Button) findViewById(R.id.button1);
btnReset.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
// resets the screen
myView.path.reset();
// Calls the onDraw() method
myView.postInvalidate();
}
});
}
}
draw_line.xml
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Clear" />
<com.example.drawline.DrawerView
android:id="#+id/custView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/button1"
android:layout_margin="5dp"
custom:lineColor="#ff0099" />
It works well with me but I want to be able to select the color of line, so I added a button in draw_line.xml that when press it show a dialog that asks the user to select color. this is the code of dialog
public void openSelectColorDialog()
{
final Dialog d = new Dialog(this);
d.setTitle("Select Color");
d.setContentView(R.layout.military_list);
int image[] = { R.drawable.black, R.drawable.blue, R.drawable.yellow};
ArrayList<HashMap<String, String>> objArayList = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < image.length; i++) {
HashMap<String, String> listData = new HashMap<String, String>();
listData.put("image", Integer.toString(image[i]));
objArayList.add(listData);
}
String[] from = { "image"};
int[] to = { R.id.list_image };
SimpleAdapter listAdapter = new SimpleAdapter(this, objArayList,
R.layout.military_list_item, from, to);
ListView lst1 = (ListView) d.findViewById(android.R.id.list);
lst1.setAdapter(listAdapter);
lst1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
if (position == 0) {
// the code of color line
d.dismiss();
} else if (position == 1) {
// the code of blue line
d.dismiss();
} else {
// the code of yellow line
d.dismiss();
}
myView.postInvalidate();
}
});
d.show();
}
What is the code I have to add to make the color like what I selected ?
consider if I write this code
DrawerView.paint.setColor(Color.BLACK);
the whole line changes its color to the selected color and this is not what I want.
I want that the color of the new line is like what I selected and keep the old lines with its colors.
Hope anyone got my mean.
Thanks in advance.
Edit
the new code is:
ColoredPath.java
public class ColoredPath {
private Paint paint;
private Path path = new Path();
private int color;
public ColoredPath() {
paint = new Paint();
color = Color.BLACK;
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(4f);
paint.setAntiAlias(true);
paint.setColor(color);
}
public ColoredPath(int color) {
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(4f);
paint.setAntiAlias(true);
paint.setColor(color);
}
public void setColor(int color){
this.color = color;
}
public int getColor(){
return color;
}
public void setPaint(Paint paint){
this.paint = paint;
}
public Paint getPaint() {
return paint;
}
public void setPath(Path path){
this.path = path;
}
public Path getPath() {
return path;
}
}
DrawerView.java
public class DrawerView extends View {
public Path circlePath = new Path();
public static int LINE_COLOR = 0;
public static boolean isTouchable = false;
public List<ColoredPath> paths = new ArrayList<ColoredPath>();
public ColoredPath currentPath;
public DrawerView(Context context, AttributeSet attrs){
super(context, attrs);
currentPath = new ColoredPath();
paths.add(currentPath);
}
public void newLine(int color){
System.out.println("in newLine method");
currentPath = new ColoredPath(color);
paths.add(currentPath);
//postInvalidate();
}
public void onButtonPress(){
// resets the screen
currentPath.getPath().reset();
// Calls the onDraw() method
postInvalidate();
}
#Override
protected void onDraw(Canvas canvas) {
System.out.println("size of paths: "+paths.size());
canvas.drawPath(currentPath.getPath(), currentPath.getPaint());
for(int i = 0; i < paths.size(); ++i) {
//ColoredPath coloredPath = paths.get(i);
canvas.drawPath(currentPath.getPath(), currentPath.getPaint());
}
}
public Path getLastPath() {
Path path = new Path();
for(int i = 0; i < paths.size(); ++i) {
path.addPath(paths.get(i).getPath());
}
return path;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isTouchable){
return false;
} else {
// Gives you x and y coordinates on the Event.
float pointX = event.getX();
float pointY = event.getY();
// Checks for the event that occurs
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
currentPath.getPath().moveTo(pointX, pointY);
//getLastPath().moveTo(pointX, pointY);
return true;
case MotionEvent.ACTION_MOVE:
currentPath.getPath().lineTo(pointX, pointY);
//getLastPath().lineTo(pointX, pointY);
circlePath.reset();
circlePath.addCircle(pointX, pointY, 30, Path.Direction.CW);
break;
case MotionEvent.ACTION_UP:
circlePath.reset();
break;
default:
return false;
}
postInvalidate();
return true;
}
}
}
and in MainActivity.java
if (position == 1) {
// blue
myView.newLine(Color.BLUE);
d.dismiss();
}
this works well and colors the lines but when I select any color it leads to remove the last line and I want all lines with there colors.
Because Path itself doesn't contain any information about it's color (color is managed by Canvas) I would suggest you to create new pair of (Path, Paint) for every new path with different paint and use only current pair in onTouch event. So here is some code which illustrate this idea
public class ColoredPath {
private Paint paint;
private Path path;
public ColoredPath(Paint paint, Path path) {
this.paint = paint;
this.path = path;
}
public Paint getPaint() {
return paint;
}
public Path getPath() {
return path;
}
}
private List<ColoredPath> paths = new ArrayList<ColoredPath>();
public DrawerView(Context context, AttributeSet attrs){
super(context, attrs);
//custom paint can be used here
paths.add(new ColoredPath(new Paint(), new Path()));
}
/////
#Override
protected void onDraw(Canvas canvas) {
for(ColoredPath coloredPath : paths) {
canvas.drawPath(coloredPath.getPath(), coloredPath.getPaint());
}
}
Where paths is List<ColoredPath>. And also you need field like ColoredPath currentPath.
I have been developing the application for drawing, and there is the code:
public class PainterView extends View implements DrawingListener {
private GestureDetector detector;
private Context context;
private Painter painter;
private Bitmap background;
private Bitmap bitmap;
private Paint bitmapPaint;
private Path path;
private Paint paint;
private float x;
private float y;
public PainterView(Context context, Painter painter) {
super(context);
this.context = context;
this.painter = painter;
detector = new GestureDetector(context, new GestureListener());
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
if (bitmap != null) {
canvas.drawBitmap(background, 0, 0, bitmapPaint);
canvas.drawBitmap(bitmap, 0, 0, bitmapPaint);
canvas.drawPath(path, paint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
detector.onTouchEvent(event);
x = event.getX();
y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
painter.touchStart(x, y);
break;
case MotionEvent.ACTION_MOVE:
painter.touchMove(x, y);
break;
case MotionEvent.ACTION_UP:
painter.touchUp();
break;
}
return true;
}
#Override
public void onPictureUpdate(Bitmap background, Bitmap bitmap, Paint bitmapPaint, Path path,
Paint paint) {
this.background=background;
this.bitmap = bitmap;
this.bitmapPaint = bitmapPaint;
this.path = path;
this.paint = paint;
invalidate();
}
public void setPainter(Painter painter) {
this.painter = painter;
}
So, the background bitmap is image (ruled paper), and I need to know how can I emulate the eraser in order to allow to user erase his notes?
you could do something like this:
public class Eraser
{
public void erase(int locX, int locY, int brushsize)
{
for(int x = locX - brushsize;x < locX + brushsize;x++)
{
for(int y = locY - brushsize;y < locY + brushsize;y++)
{
map.setPixle(x,y,Color.white);
}
}
}
private Bitmap map;
}
This is a square eraser, I'm sure you could figure out a way to make it a circle if you really wanted to. I hope his helped!