Search code examples
androidandroid-custom-viewright-to-left

Supporting RTL locales when drawing in custom views


When I draw in my custom view using the Canvas, is there a simple way to draw for RTL locales without manually inverting coordinate calculations?

As a very contrived example, here is a custom View with the following in onDraw():

int w = getWidth();
int h = getHeight();
canvas.save();

mPaint.setColor(Color.RED);
canvas.drawRect(0, 0, w / 2, h, mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawRect(w / 2, 0, w, h, mPaint);

int size = h / 4;
mPaint.setColor(Color.GREEN);
int paddingEnd = ViewCompat.getPaddingEnd(this);
canvas.translate(-paddingEnd, getPaddingTop());
canvas.drawRect(w - size, 0, w, size, mPaint);

canvas.restore();

It appears exactly the same in LTR and RTL layouts:

enter image description here

I know you can flip the Canvas using a Matrix or canvas.scale(), but this is not a viable option for more complicated scenarios, such as drawing text or other Drawables on the Canvas.

What is the best way to accomplish RTL drawing on a Canvas? Do I literally have to calculate inverted values for X-axis coordinates?


Solution

  • As far as I could find, there isn't anything in the framework that automatically handles transforming the canvas (for drawing, as in this case) or that handles positioning views (for layout). In other words, I have to do that work myself using View.getLayoutDirection() to determine the layout direction and calculate accordingly. Since most drawing code works with the left position of the object, you can usually do something like

    if (isRtl) {
        left = width - shapeWidth - left;
    }
    

    where width is the width of the canvas (or the area of the canvas you are drawing in, e.g. if you've already subtracted the amount consumed by left and right padding), and shapeWidth is the shape width. Then you add the shape width to left to get the right value.

    A similar approach can be used for laying out child views.