I'm trying to draw a rectangle above the google map to crop a portion of the map.
I placed a googleMap and a custom layout with a canvas like this.
<FrameLayout>
<FrameLayout/>//conatiner for SupportMapFragment
<MyCustomLayout/>
</FrameLayout>
Inside MyCustomLayout, the paints are initiated like this.
linedPaint.setStyle(Paint.Style.STROKE);
linedPaint.setStrokeWidth(5f);
linedPaint.setColor(getResources().getColor(R.color.colorBlack));
linedPaint.setPathEffect(new DashPathEffect(new float[]{10, 10}, 0));
bgPaint = new Paint();
bgPaint.setColor(0x70FFFFFF);
transparentPaint = new Paint();
transparentPaint.setStyle(Paint.Style.FILL);
transparentPaint.setColor(getResources().getColor(android.R.color.transparent));
transparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
onDraw is as below.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
try {
canvas.drawRect(0, 0, getWidth(), getHeight(), bgPaint);
canvas.drawRect(mClickStartX, mClickStartY, mClickEndX, mClickEndY, transparentPaint);
canvas.drawRect(mClickStartX, mClickStartY, mClickEndX, mClickEndY, linedPaint);
} catch (Exception e) {
ErrorController.showError(e);
}
}
This will draw a dim white background above the map, and when the user clicks and drags on it, it will draw a transparent rectangle.
But, when the transparentPaint's xfermode is set to PorterDuff.Mode.CLEAR, it clears the map itself, resulting as a black rectangle shown as below.
When changing the xfermode to OVERLAY, it doesn't change the map to black, but the background of the canvas will not be changed as I expect.
When switching to a Naver Map fragment, it works as I expect it to be. What can I try to make this work? Please help!
Related
I've got a simple layout with 2 imageViews:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="#+id/takenPicture"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.example.dochjavatestimplementation.pkgActivity.ExtendedImageView
android:id="#+id/takenPicture2"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
The first ImageView displays a bitmap, the second ImageView (1) is a custom ImageView (ExtendedImageView) (2)which draws a canvas which gets displayed on top of the normal ImageView.
This looks like this:
displayimageviews
What I want is that after drawing the rect in my onDraw method, I want to clear the rect again (right now just for testing purposes). This is what my code looks like:
#Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
canvas.drawRect(new Rect(212,0,-720,600),paint);
//clear the rect/contents of canvas again
//try 1
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
//try2
Paint transparent = new Paint();
transparent.setAlpha(0);
canvas.drawPaint(transparent);
//try3
setImageResource(0);
}
I tried clearing the canvas/rect in three different ways as seen in code above, but it doesnt change the output as the black rect is still visible.
My question now is what can the cause be? Is it cause I'm not "updating" the canvas or is it due to how I try clearing my canvas?
The endresult should basically be that I only see the first imageview
Drawing shapes on Canvas in View.onDraw() is low-level function that directly changes pixels on the display in the final stage. So, if you once draw something, it's impossible to erase it. It's not buffered. There remain only mixed RGB(w/o A) pixels on the screen. The former pixel colors (originated from the "takenPicture") are already lost.
If you'd like to make shapes erasable, prepare another canvas backed by an ARGB-bitmap and draw all on it. Then draw the bitmap on the canvas in the end.
#Override
protected void onDraw(Canvas canvas)
{
// Prepare Bitmap and Canvas
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas draw_canvas = new Canvas(bitmap);
// Draw a rect.
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
draw_canvas.drawRect(new Rect(212,0,-720,600),paint);
// Clear
draw_canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
// Draw the bitmap.
canvas.drawBitmap(bitmap, 0, 0, null);
bitmap.recycle();
}
At the first of my game, I draw some circles from alpha 0 to 255 using canvas(it's like making a fade_in animation by myself)
But if you see in picture(this picture captured in alpha 230),from alpha 0 to 254 these circles aren't smooth!(click on picture to see what I mean)
(and only when alpha become 255 the circles become smooth)
What's the problem and how can I fix this?
my code:
I have a game loop, that get canvas
canvas = gameView.getHolder().lockCanvas();
then in my view ,at first I set :
paintAlpha = 0;
paint = new Paint();
paint.setAntiAlias(true);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAlpha(paintAlpha);
paint.setColor(Color.parseColor(color));
then in every loop(every ticks) I do this:
if(paintAlpha < 255) {
paintAlpha+=1;
paint.setAlpha(paintAlpha);
}
canvas.drawCircle(cx, cy, currentRadius, paint);
Solution:
Thanks to #nitesh.
The problem was because of surfaceView that can't set anti alias to canvas (in View you don't have this problem ,I don't know why)
By using Bitmap and draw on it and finally draw bitmap by canvas , the problem solved (instead of drawing on canvas directly)
Set the following property to paint object
paint.setAntiAlias(true);
For better understanding and other approaches refer this link
https://medium.com/#ali.muzaffar/android-why-your-canvas-shapes-arent-smooth-aa2a3f450eb5#.p9iktozdi
From the article
Draw a bitmap first if:
- You need to persist the image.
- You need to draw transparent pixels.
- Your shapes don’t change often and/or require time consuming operations.
Use anti-aliasing to draw smooth edges.
Avoid redraws on the bitmap if possible or else, clear a bitmap before redrawing.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(200,
200,
Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
}
bitmapCanvas.drawColor(
Color.TRANSPARENT,
PorterDuff.Mode.CLEAR); //this line moved outside if
drawOnCanvas(bitmapCanvas);
canvas.drawBitmap(bitmap, mLeftX, mTopY, p);
}
protected void drawOnCanvas(Canvas canvas) {
canvas.drawCircle(mLeftX + 100, mTopY + 100, 100, p);
}
you can approach this by
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
or
paint.setAntiAlias(true);
I'm working with canvas im my application and I need to draw a circle.
To do that, I'm using the drawCicle(cx, cy, radious, paint) method for the canvas class.
The problem is that the circle's edges appear pixellated. And its kinf of oval.
This is my code:
public void drawCircle(){
Paint paint = new Paint();
paint.setColor(Color.rgb(52, 73, 94));
canvas.drawCircle(200, 300, 33, paint);
}
Use paint.setFlags(Paint.ANTI_ALIAS_FLAG)
This enables anti-aliasing => edges become smoother
I am drawing a grid and I want it to be larger than the screen size so that a user can drag the screen left/right/up/down to get to the rest of the grid.
What is the best way to do that? I've tried drawing a larger bitmap to the canvas, but didn't get anywhere.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
Bitmap testBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888);
canvas.drawBitmap(testBitmap, 0, 0, paint);
canvas.drawPaint(paint);
//other grid drawing code here
}
I used the View's scrollBy() method in the onTouch method of the Activity. It worked.
You can probably use the canvas.translate(x, y) method. That will adjust the origin for your canvas in relation to the screen. So canvas.translate(10, 10) will make you canvas origin (0, 0) be at the point of (10, 10) on the screen. Use a negative translation to scroll the screen.
I have a SurfaceView where I'm setting a background color and an image like so:
BitmapDrawable tiledBackground = new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.background));
tiledBackground.setTileModeX(Shader.TileMode.REPEAT);
tiledBackground.setColorFilter(0xaacceeff, PorterDuff.Mode.DST_OVER);
this.setBackgroundDrawable(tiledBackground);
I also have an animation thread where I'm drawing an image (successively adjusting its x coordinate so that it appears to move to the left). The background image is a transparent PNG and so some parts of it are transparent. It appears that the image I'm drawing from the thread appears below the background drawable on the SurfaceView. How can I have it appear on top of the background? I'm drawing the image like so:
private void doDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(missile, x, getHeight() - 95, paint);
canvas.restore();
}
missile and paint are initialized in the constructor of the thread to:
missile = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.missile));
paint = new Paint();
Each call to doDraw should draw everything you want to be displayed, including the background.
// Add to initializer
tiledBackground = new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.background));
tiledBackground.setTileModeX(Shader.TileMode.REPEAT);
tiledBackground.setColorFilter(0xaacceeff, PorterDuff.Mode.DST_OVER);
private void doDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
// Create a rectangle (just holds top/bottom/left/right info)
Rect drawRect = new Rect();
// Populate the rectangle that we just created with the drawing area of the canvas.
canvas.getClipBounds(drawRect);
// Make the height of the background drawing area equal to the height of the background bitmap
drawRect.bottom = drawRect.top + tiledBackground.getBitmap().getHeight();
// Set the drawing area for the background.
tiledBackground.setBounds(drawRect);
tiledBackground.draw(canvas);
canvas.drawBitmap(missile, x, getHeight() - 95, paint);
canvas.restore();
}