I am writing a custom renderer for Xamarin.Forms. I am overriding the class ImageRenderer to do some tweaks to the image.
However, I want to overlay some parts of the image with circles, so I override the method void OnDraw(Canvas canvas).
Then I modify the Canvas a bit by drawing some circles:
protected override void OnDraw(Canvas canvas)
{
var paint = new Paint
{
Color = Color.Red
};
paint.SetStyle(Paint.Style.Fill);
foreach (var mapObject in _control.PointSource)
{
canvas.DrawCircle(mapObject.Location.X, mapObject.Location.Y, 100 / _scaleFactor, paint);
}
base.OnDraw(canvas);
}
However, everything is drawn on the background. The actual image is always on top. How can one draw circles on top of the image?
https://developer.xamarin.com/api/member/Android.Views.View.OnDraw/
In the docs they say the following:
the canvas on which the background will be drawn
So the current behaviour was expected.
I managed to fix it by moving the circle logic to the function: void Draw(Canvas canvas).
Related
So I have a custom View which has a BitmapDrawable as its background which I draw to:
public void onDraw(Canvas canvas){
super.onDraw(canvas);
draw_game_map();
draw_player();
draw_overlay_with_circle();
}
(each of these methods just draws bitmap(s))
Now I'm calling View.draw(Canvas) 60 times per second and it works fine, except I want to have something like this:
public void onDraw(Canvas canvas){
super.onDraw(canvas);
//From this point, don't show what I'm about to draw
draw_game_map();
draw_player();
draw_overlay_with_circle();
//Show what I just drew
}
Any code I can add to only display the changes made only after I'm done drawing, rather than during?
I'm going through a for loop over elemets of a synchronized ArrayList inside the draw method of a SurfaceView like this:
public void draw(Canvas canvas) {
for(MyObject o : system) {
canvas.drawPath(o.getPath(), mPaint);
canvas.drawCircle(o.getX(), o.getY(), radius, mPaint);
}
}
The problem is that this will draw next elements in the list on top of previous elements. There is a way to make the paths drawn behind all circles without proliferation of for loops?
I have 3 ImageViews. 1st and 2nd connected with red line. Also I have simple button. Here is a picture:
I want to connect 2nd & 3rd ImageViews with new Path line and change the first line color (for example to Green) when i clicking my button. Here is parts of my code:
public class SkillPath extends View {
Paint paint;
Path path;
... constructors
#Override
protected void onDraw(Canvas canvas) {
addPath (canvas);
}
//Here is my RED line
void addPath (Canvas canvas){
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
path.moveTo(110, 110);
path.lineTo(210, 110);
canvas.drawPath(path, paint);
Log.d ("Page 2","onDraw");
}
I can get all coordinates of all Views, but how can I redraw existing canvas? I suspect, I need to use invalidate(), but I do not know enough to do this. Need help.
The invalidate() method forces the View to be re-drawn.
So just apply the modification you need on your canvas and call invalidate() on the related View after these modifications.
I would like to send each time different Drawable shape to view and then add it to my activity.
The problem is I can't find a way to add the drawable shape into the canvas when I'm overriding the onDraw method.
The design supposed to be reusable, I can draw rect first and then draw circle...
I want to find a way to send the view different shape. Is it possible?
#Override
protected void onDraw(Canvas canvas) {
// Draw the ball
ballBounds.set(ballX-ballRadius, ballY-ballRadius, ballX+ballRadius, ballY+ballRadius);
paint.setColor(Color.GREEN);
// canvas.drawOval(ballBounds, paint);
canvas.drawRect(ballBounds, paint);
}
Although, your question needs more explanation on what you need, but with what I could understand is you want rect, or circle on desire, here it is,
Add, global variable int ShapeStructure = 0;
#Override
protected void onDraw(Canvas canvas)
{
// Draw the ball
ballBounds.set(ballX-ballRadius, ballY-ballRadius, ballX+ballRadius, ballY+ballRadius);
paint.setColor(Color.GREEN);
if(ShapeStructure == 0){
canvas.drawOval(ballBounds, paint);
}else{
canvas.drawRect(ballBounds, paint);
}
}
Now that, you have a variable at your disposal, you can control what you want to paint.
Hope, this helps, let me know if you want something else.
I'm extending LinearLayout:
public class MyLinearLayout extends LinearLayout {
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(0xFFFF0000);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
}
}
If the layout has child elements, shouldn't the red line above be drawn on top of them? Considering a layout like:
<MyLinearLayout>
<ImageView />
</MyLinearLayout>
I'd expect to get the red line drawn above the child ImageView. But it gets drawn below it. I was assuming all child drawing would have been completed after the super.onDraw() line is finished.
Is there a way to get to the canvas and draw something on it after all child drawing has been completed?
Thanks
Layouts don't draw unless you call setWillNotDraw(false);. They do that for efficiency reasons.
EDIT:
onDraw() really is meant to just allow you to modify the Canvas before the drawing operation happens. It doesn't actually draw. What you want to do is override draw() like so:
#Override
protected void draw(Canvas canvas) {
super.draw(canvas);
Paint paint = new Paint();
paint.setColor(0xFFFF0000);
canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
}
Calling the super will draw all the children in the view. Then it will draw all the lines. I do still believe you need setWillNotDraw(false) to be called though.
I'm rewriting my answer as I hadn't seen your line of code where you were drawing to the canvas.
The canvas like some other graphics environments is inverted. So calling getHeight() is actually drawing the line at the bottom. Instead call
canvas.drawLine( 0, 0, getWidth(), 0, paint);
This means draw the line at the top, across the width of the view.
Also, calling super first paints the children prior to any custom painting so your fine there.
If you have a LinearLayout and you need:
draw all of its children first, like buttons, image views
then, on top of those components, draw something directly on the canvas.
You can try this:
public class YourClass extends LinearLayout
{
#Override
protected void dispatchDraw(Canvas canvas)
{
super.dispatchDraw(canvas);
// do your custom drawings afterwards
canvas.drawCircle...
canvas.drawLine...