How to Draw Outside the Bounds of an Android Canvas

Drawing outside of the view bounds, over multiple parent ViewGroups

Simple answer: You can't draw outside the view's bounds.

<RelativeLayout>
<RelativeLayout
android:width="400dp"
android:height="400dp">

<LineChartView
android:width="100dp"
android:height="100dp"/>

<RelativeLayout>
</RelativeLayout>

In the above case, if you check the Canvas size in LineChartView's onDraw(canvas), you will find the height and width are 100dp. And that is the size of your View. So you can draw only within that space. The parent of your View doesn't really have any impact, unless you set your View's width/height as a dynamic value like MatchParent or WrapContent. If you do MatchParent on your View, then the width/height of the Canvas becomes 400dp.

In essence, the size of the Canvas determines what space is available to draw and what is visible on screen. To solve your use case, you could make you LineChartView fill the entire screen. But with this approach, you will have to keep track of where to draw the actual graph. If the screen is scrollable, then it will add more complexity.

The other approach, which I think is the easy one, is to have two views (One for the LineChart, and the other for the PopUp). The LineChartView will draw the actual graph, and the PopUp view will cover the entire screen. When the user selects something in the graph, you just need to pass the Graph's values along with the Absolute position on where to draw the popUp to the PopUpView. This way you can draw the popUp anywhere on the screen.

Draw Rectagle with fill outside bounds

I'm still not entirely sure what you're trying to accomplish. The shape you show can be drawn as follows:

// set up some constants
int w = canvas.getWidth();
int h = canvas.getHeight();
RectF rect = new RectF(100, 100, w - 100, h - 100);
float radius = 10.0f; // should be retrieved from resources and defined as dp
float borderWidth = 2.0f; // ditto
int innerRectFillColor = 0x33000000; // or whatever shade it should be

// first fill the interior
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(innerRectFillColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rect, radius, radius, paint);
// then draw the border
paint.setColor(Color.WHITE);
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(rect, radius, radius, paint);

If instead you want to draw around a hole (so the background shows through), the trick of drawing the surrounding rectangles won't work because of the rounded corners (the border also makes it more complicated). Instead, you can create a separate Bitmap that has a transparent hole and then draw that. You'll need to use a Porter-Duff transfer mode of CLEAR to punch the hole in the bitmap:

// same constants as above except innerRectFillColor is not used. Instead:
int outerFillColor = 0x77000000;

// first create an off-screen bitmap and its canvas
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas auxCanvas = new Canvas(bitmap);

// then fill the bitmap with the desired outside color
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(outerFillColor);
paint.setStyle(Paint.Style.FILL);
auxCanvas.drawPaint(paint);

// then punch a transparent hole in the shape of the rect
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
auxCanvas.drawRoundRect(rect, radius, radius, paint);

// then draw the white rect border (being sure to get rid of the xfer mode!)
paint.setXfermode(null);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
auxCanvas.drawRoundRect(rect, radius, radius, paint);

// finally, draw the whole thing to the original canvas
canvas.drawBitmap(bitmap, 0, 0, paint);

How to draw outside view bounds?

I'm drawing the conclusion that the right way is to do what I proposed - create a transparent view that is at the top of the z-order for the space you need to draw in.

I come to this conclusion after learning how the Navigation Drawer drawing works - exactly in this way. So, if Google uses this technique, I conclude that it's the best way available.

Android Canvas - restrict draw area

What you want is Canvas.clipRect(). You will need to know the bounds of the clipping rectangle, of course, but you don't need to worry about calculating a custom srcRect.

To use, save() the Canvas, do a single drawBitmap(), then restore() it to get your original clipping state back:

canvas.save();
canvas.clipRect(...);
canvas.drawBitmap(...);
canvas.restore();


Related Topics



Leave a reply



Submit