RTL Support on Android — Here’s all you need to know

--

There comes a point in an app’s lifecycle when you decide to widen your audience. Although your app works great and your daily downloads are off the charts, not everyone is happy. Why?🤔

No RTL (Right to Left) Layout support.

A few languages — like Arabic, Hebrew or Persian — are written from Right to Left. To handle them, Android supports RTL layouts from API 17+ i.e., Android 4.1 (Jelly Bean).

Getting Started

  • In order to support RTL in your app, you first need to add android:supportsRtl="true" to the <application> element in your manifest file.

Woohoo… 🎉 Done!!! Your app now supports RTL. But lets see how it looks. You can check your app in RTL mode by doing one of two things.

  • Select one of the RTL languages as your device language.
  • Or from Developer Options in Settings, check Force RTL layout Direction. I find this option more convenient but, do note, this does not change your System language.

XML Layouts

You’ll need to make the following changes in all your Layouts

  • If your app only supports API ≥ 17, replace all the layout_marginLeft/layout_marginReft/paddingLeft/paddingRight or any other Left and Right layout property with Start and End equivalent. For example android:paddingLeft will be replaced with android:paddingStart.
  • If your app supports API<17 then instead of replacing the Left and Right layout properties, add their Start and End layout property equivalent alongside.

There is a much easier way to do the above changes without going through all the files and then doing it manually. Android Studio can do this for you. Just go to Android Studio > Refactor > Add RTL support where possible…

I would recommend checking your app once after applying this change as you might not want all your Layouts/Views to be RTL. If you want to force any layout to LTR then just add android:layoutDirection="ltr" to that view.

Drawables

Time to search for all those drawables that you’d want to mirror for RTL. Since resources can have variants based on device aspects like Orientation, Screen Density, API version, you can also have variants for different Layout Directions i.e., RTL or LTR. All you need to do is add the RTL variants of the drawables that you want to be mirrored.

📌 Small Tip :

If your Toolbar defines back arrow nav icon like this
app:navigationIcon="?attr/homeAsUpIndicator"
This back button is consistent with Layout Directions.
But only works on API 23+ 😣, below that it just points Left.

And what if you don’t have RTL variant for your drawables? You can use android:autoMirrored="true". But this works on api 19+ only. If you want to mirror Drawables or any View on API <19, there is sort of a temporary workaround that can come in handy. You can just add android:rotationY="@integer/locale_mirror_flip" to the View you want to be mirrored. And define

res/values/integers.xml

<integer name="locale_mirror_flip">0</integer>

res/values-ldrtl/integers.xml

<integer name="locale_mirror_flip">180</integer>

I used this trick to mirror a Progress Indicator that doesn’t support RTL. This works on API 11+.

Animations

Animations that use X axis for transitions will not work properly. For example TranslateAnimation — You will need to add a RTL variant for these as well.
For example: android:fromXDelta="-100%p" will become android:fromXDelta="100%p" in RTL variant of this animation,
android:pivotX="25%" will become android:pivotX="75%".

Java Files

I would recommend defining all animations, layout, etc as xml resource only. Because RTL support for those programmatically defined layouts and animations is painful. Also, the compilation will take more time if you modify a Java file instead of XML.

If you still find these defined in your java files then this is what you’ll need to do:

  • Programmatically defined Animations with X axis values need to have different values for RTL, as the X axis always starts from Left in both layout directions. Basically any X anywhere in android means from left.
  • If you have setMargin(left, top, right, bottom) then also add setMarginStart(start) and setMarginEnd(end).
  • setPadding(left, top, right, bottom) will be replaced with setPaddingRelative(start, top, end, bottom).
  • setGravity(Gravity.LEFT/RIGHT) will be replaced with setGravity(Gravity.START/END).
  • Any other layout property like LayoutParams rules for RelativeLayoutwill also need to be changed.
  • All those Horizontal RecyclerView, ListView, ViewPager, etc will need your attention as well.
    For Example: A Horizontal RecyclerView can use setStackFromEnd(true)on it’s LayoutManager in case of RTL layout.
  • If you want Layout Direction of a View on runtime then use
    ViewCompat.getLayoutDirection(view)
    Note: This always returns LTR if called from the Constructor of a View.
  • If you want Layout Direction from a Context then use
    Configuration config = context.getResources().getConfiguration();
    if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
    //RTL
    }

Extras

If you have completed all of the above then I believe you should have pretty good RTL Support. There are few more things you can look at for your final touch.

  • TextAlignment
  • TextDirection

Conclusion

Support for RTL is not that difficult on Android. I wish I had supported it from day 1 instead of doing it at a later stage. If you found something missing or have suggestions then do comment.

Rishabh Harit is an Android Developer at Crowdfire.

*This post was first published on Rishabh’s Medium

--

--