0

I have two images: one that is an empty jar, and one that is the same jar but with a fill. My goal is to use a custom renderer to draw the empty jar, do a calculation of the percentage, and then copy a subset of the full jar onto the empty one to simulate the jar responsively filling based on a value. To do this, I am making a custom ImageRenderer.

I have overridden the Draw() class as follows:

public override void Draw(Canvas canvas)
    {
        base.Draw(canvas);

        //Draw the fill
        GoalJarView handle = (GoalJarView)this.Element;
        int startY = (int)(canvas.Height - Math.Floor(canvas.Height * (handle.CurrentValue / handle.GoalValue)));
        Rect bounds = new Rect(0, startY, canvas.Width, canvas.Height); 
        Bitmap bmp = BitmapFactory.DecodeResource(this.Context.Resources, Resource.Drawable.jar_fill);
        canvas.DrawBitmap(bmp, bounds, bounds, null);
    }

For some reason, this results in the correct image being drawn, but for whatever reason it is upside down and in the wrong place:

enter image description here

The weird thing is, if I change the src rectangle to null, it displays in the correct location, right-side up, but not cropped.

canvas.DrawBitmap(bmp, null, bounds, null);

enter image description here

Why is Android flipping this image?

w0f
  • 908
  • 9
  • 23

1 Answers1

0

You have to take into consideration that your Drawable is not the same size as your View's canvas (assuming you are using a ImageView subclass) You have to scale the bitmap to your view's canvas thus your src and dst rectangles are not the same.

Here is an example:

protected override void OnDraw(Canvas canvas)
{
    base.OnDraw(canvas);
    if ((Current > Max) || (Current <= 0.0)) return;
    var percentComplete = Current / Max;
    var overlayYFrom = (int)(overlayBitmap.Height - (overlayBitmap.Height * percentComplete));
    var overlayYTo = (int)(canvas.Height - (canvas.Height * percentComplete));
    var drawRectFrom = new Rect(0, overlayYFrom, overlayBitmap.Width, overlayBitmap.Height);
    var drawRectTo = new Rect(0, overlayYTo, canvas.Width, canvas.Height);
    canvas.DrawBitmap(overlayBitmap, drawRectFrom, drawRectTo, null);
}

Note: If your base image is not filling the entire widget, you will see a mismatch in the two images as you partially draw on top of the other.

Note: BitmapFactory.DecodeResource is a heavy API call and you should cache the bitmap instead of calling it every Draw cycle. (You might want to cache a scaled version of the original drawable to optimize memory)

SushiHangover
  • 73,120
  • 10
  • 106
  • 165