i want the eraser to erase smoothly but in my activity by default it erase the lines on touch draw and erase the lines on touch is not proper.my code what i had worked on.
public void Draw(){
count=1;
bmp = Bitmap.createBitmap(fullimage2.getWidth(), fullimage2.getHeight(), Config.ARGB_8888);
c = new Canvas(bmp);
fullimage2.draw(c);
if(mode==0){
pnt.setColor(Color.BLACK);
pnt.setStyle(Paint.Style.STROKE);
pnt.setStrokeJoin(Paint.Join.ROUND);
pnt.setStrokeCap(Paint.Cap.ROUND);
pnt.setStrokeWidth(8);
c.drawPath(path,pnt);
}
else{
pnt1.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
pnt1.setStrokeWidth(25);
pnt1.setStrokeCap(Paint.Cap.ROUND);
pnt1.setColor(Color.TRANSPARENT);
pnt1.setAlpha(0);
c.drawPath(path1,pnt1);
pnt1.setStyle(Style.STROKE);
pnt1.setMaskFilter(null);
pnt1.setAntiAlias(true);
}
Is the code you use to draw proper? Otherwise use the same code and for the erraser use the same color as your background. If you need better code to draw, ask!
Related
I am fairly new to Android, but why isn't my image showing on the canvas?
I know that it is working properly because the background color is black, which I changed in the same same method, onDraw . Can anyone help me? Thanks in advance!
public PongView(Context context) {
super(context);
paddle1 = BitmapFactory.decodeResource(getResources(), R.drawable.pongpaddle);
paddle2 = BitmapFactory.decodeResource(getResources(), R.drawable.pongpaddle);
}
protected void onDraw(Canvas canvas) {
xp1 = canvas.getWidth()/2;
xp2 = canvas.getWidth()/2;
yp1 = 25;
yp2 = 760;
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(paddle1, xp1,yp1, null);
canvas.drawBitmap(paddle2,xp2,yp2, null);
Paint white = new Paint();
white.setColor(Color.WHITE);
canvas.drawText("Score P1:"+ p1Score +" P2: " + p2Score , 700, 20,white );
}
Based on your comment above, I think what's happening is, android run time is drawing to the canvas, and your onDraw is not being called. You can avoid this by calling this.setWillNotDraw(false) in your class' constructor. Once you clear this flag, your onDraw() will be called.
Source: Android developer docs says if you override View's onDraw(), you have to clear this flag. Check setWillNotDraw
I'm implementing custom path effect for route on top of MapView and I came up with the problem how to make my beginning and ending of the path rounded (like Paint.setStrokeCap(Cap.ROUND) does). See screenshot - black lines - is my route I want to round at the end
Here is how I implemented my custom PathEffect:
public RouteOverlay(Context context)
{
mContext = context;
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(COLOR_DEFAULT);
mPaint.setAntiAlias(true);
mPaint.setStrokeCap(Cap.ROUND); // this one does not work...
mPaint.setStrokeJoin(Join.ROUND);
PathEffect e1 = new PathDashPathEffect(createRouteLineStyle(), 10, 3, PathDashPathEffect.Style.MORPH);
PathEffect e2 = new CornerPathEffect(10);
mPaint.setPathEffect(new ComposePathEffect(e1, e2));
}
private Path createRouteLineStyle()
{
Path p = new Path();
p.moveTo(-5, ROUTE_LINE_WIDTH/2);
p.lineTo(5,ROUTE_LINE_WIDTH/2);
p.lineTo(5,ROUTE_LINE_WIDTH/2-currentThickness);
p.lineTo(-5, ROUTE_LINE_WIDTH/2-currentThickness);
p.close();
p.moveTo(-5, -(ROUTE_LINE_WIDTH/2));
p.lineTo(5,-(ROUTE_LINE_WIDTH/2));
p.lineTo(5, -(ROUTE_LINE_WIDTH/2-currentThickness));
p.lineTo(-5, -(ROUTE_LINE_WIDTH/2-currentThickness));
return p;
}
#Override
public void draw(Canvas canvas, final MapView mapView, boolean shadow)
{
if(shadow) return;
if(mDrawEnabled)
{
synchronized(mPoints)
{
canvas.drawPath(mPath, mPaint);
}
}
}
As you can see on the screenshot, the ending of the line is not rounded (as well as beginning...). setStrokeCap(Cap.ROUND) doesn't help.
So the question is - how to add round cap to my custom path? I was thinking of using addArc() or addCircle() to the end (and beginning) of my path, but this doesn't seem right.
The reason why I need custom path effect - is that I need to draw the route around actual road - so route should be empty inside and have inner and outer stroke lines.
In case somebody knows how to make this kind of path effect in some other way - please let me know, because this solution has big cons I have to deal with..
I don't see any reason why that should not work unless you are running into the problem mentioned here http://code.google.com/p/android/issues/detail?id=24873.
I managed to find a solution for my problem.
So I got rid of my custom path effect and started to use usual stroke (where stroke cap works as expected). So I basically draw my path 2 times: at first I draw black line, after that I draw thiner transparent line to clear the center of previous black line.
The only trick in this approach is that I need to draw my path in a separate bitmap (using temp canvas) and when path bitmap is ready - render it to the main canvas.
#Override
public void draw(Canvas canvas, final MapView mapView, boolean shadow)
{
//Generate new bitmap if old bitmap doesn't equal to the screen size (f.i. when screen orientation changes)
if(pathBitmap == null || pathBitmap.isRecycled() || pathBitmap.getWidth()!=canvas.getWidth() || pathBitmap.getHeight()!=canvas.getHeight())
{
if(pathBitmap != null)
{
pathBitmap.recycle();
}
pathBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
tempCanvas.setBitmap(pathBitmap);
}
//Render routes to the temporary bitmap
renderPathBitmap();
//Render temporary bitmap onto main canvas
canvas.drawBitmap(pathBitmap, 0, 0, null);
}
}
private void renderPath(Path path, Canvas canvas)
{
routePaint.setStrokeWidth(ROUTE_LINE_WIDTH);
routePaint.setColor(OUTER_COLOR);
routePaint.setXfermode(null);
canvas.drawPath(path, routePaint); //render outer line
routePaint.setStrokeWidth(ROUTE_LINE_WIDTH/1.7f);
routePaint.setColor(Color.TRANSPARENT);
routePaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
canvas.drawPath(path, routePaint); //render inner line
}
So result looks like:
What I want, the text is being moved with the finger touch over the image, on the button click it redraws the existing Image into a new one which is as text pasted on it.
it works fine for v3.1 as well as on Emulator.
but i tried to test on v2.2 device it occurs the forse Close.While it has all support for the Devices.Can you help me out of here.Its gonna be crucial in few weeks.Thanks in advance.
///Redrawing the image & touchin Move of the Canvas with text
public void redrawImage(String path,float sizeValue,String textValue,int colorValue) {
BitmapFactory.Options options = new BitmapFactory.Options();
try {
options.inMutable = true;
} catch (Exception e) {
// TODO: handle exception
System.out.println("#############Error is======"+e.getMessage());
}
Bitmap bm = BitmapFactory.decodeFile(path,options);
proxy = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);
Canvas c = new Canvas(proxy);
//Here, we draw the background image.
c.drawBitmap(bm, new Matrix(), null);
Paint paint = new Paint();
paint.setColor(colorValue); // Text Color
paint.setStrokeWidth(30); // Text Size
paint.setTextSize(sizeValue);
System.out.println("Values passing=========="+someGlobalXvariable+", "+someGlobalYvariable+", "
+sizeValue+", "+textValue);
//Here, we draw the text where the user last touched.
c.drawText(textValue, someGlobalXvariable, someGlobalYvariable, paint);
popImgae.setImageBitmap(proxy);
}
It would help to know when the force close happens, like right after the app starts, as soon as you touch before text ever draws?
Debug on the device
A pretty easy and fullproof technique is running the code in debug mode on the actual device. Add a breakpoint at the beginning of your function and step over each line until it force closes.
Possibly OOM
If you are calling redrawImage repeatedly, like every frame during a touch, then allocating of a new bitmap may eat a lot of memory quickly and cause the crash:
Bitmap bm = BitmapFactory.decodeFile(path,options);
Then the force close might happen after a bit. Try changing bm to a method param or member field that is allocated and read from file once.
Here I need to remove paints.I did paints using surfaceview.inside erase button I use below code. Now when I click erase button the drawn paints all erased.But now again draw means paints not visible.please any one help me.
public void onClick(View view){
if(view==erasebtn)
{
if (!currentDrawingPath.isEmpty()) {
currentPaint .setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
action=true;
}
}
}
If you want to completely erase all drawing you have to fill it with the "empty" color.
Assuming you have a canvas in which you draw:
canvas.drawColor(Color.WHITE);
If you have drawn lines etc in a Canvas where you just add your drawings all the time then you need to create a way to restore an older version of that. Changing the Paint you have used to draw things will not change the things you have already drawn. It just affects how any future drawing is done.
There are several possibilities to do that e.g. the following should work:
Bitmap bitmap = Bitmap.createBitmap(400, 400, null);
Canvas canvas = new Canvas(bitmap);
ByteBuffer buffer = ByteBuffer.allocate(bitmap.getByteCount());
//save the state
bitmap.copyPixelsToBuffer(buffer);
// draw something
canvas.drawLine();
// restore the state
bitmap.copyPixelsFromBuffer(buffer):
That way you could go back 1 state. If you need to undo more steps think about saving Bitmaps to disk since it will consume quite a lot of memory otherwise.
Another possibility is to save all those steps you have drawn numerically in a list (like a vector graphic) in a way that you can redraw the full image up to a certain point - then you can just undo drawing by drawing just the first part of your list to a fresh image.
Edit: Would it work if you add this to the code and use it instead of undo()?
// add me to the code that has undo()
public void undoAll (){
final int length = currentStackLength();
for (int i = lenght - 1; i >= 0; i--) {
final DrawingPath undoCommand = currentStack.get( i );
currentStack.remove( i );
undoCommand.undo();
redoStack.add( undoCommand );
}
}
I want to use my image to replace the Compass image of MyLocationOverlay, how can i implement?
Subclass MyLocationOverlay, override the method drawCompass(Canvas canvas, float bearing), and draw your own bitmap(s) onto the canvas object:
#Override
protected void drawCompass(Canvas canvas, float bearing) {
Resources res = _context.getResources();
Bitmap myCompassPointer = BitmapFactory.decodeResource(res, R.drawable.compass_pointer);
float rotationAngle = -bearing + 360f;
Matrix rotation = new Matrix();
rotation.preRotate(rotationAngle, myCompassPointer.getWidth()/2.0f, myCompassPointer.getHeight()/2.0f);
canvas.drawBitmap(myCompassPointer, rotation, null);
// don't call super if you don't want the default compass image:
//super.drawCompass(canvas, bearing);
}
I think you can only replace the Marker (the blue, pulsating dot) which displays the location, please see a related StackOverflow question. Hope this helps, even if the issue seems a bit old.