RTL Support on Android. Here is 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 you have a huge number of daily downloads, not everyone is happy. Why 🤔? No RTL (Right to Left) Layout support.
Few languages such as Arabic, Hebrew, or Persian are written from Right to Left. To handle them, Android supports RTL layouts from API 17+
i.e., Android 4.2 (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
inSettings
, checkForce 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 thelayout_marginLeft/layout_marginReft/paddingLeft/paddingRight
or any otherLeft
andRight
layout property withStart
andEnd
equivalent. For exampleandroid:paddingLeft
will be replaced withandroid:paddingStart
. - If your app supports
API<17
then instead of replacing the Left and Right layout properties, add theirStart
andEnd
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 you 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 would want to be mirrored 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 use this trick to mirror one of the 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 theX 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 addsetMarginStart(start)
andsetMarginEnd(end)
. setPadding(left, top, right, bottom)
will be replaced withsetPaddingRelative(start, top, end, bottom)
.setGravity(Gravity.LEFT/RIGHT)
will be replaced withsetGravity(Gravity.START/END)
.- Any other layout property like
LayoutParams
rules forRelativeLayout
will also need to be changed. - All those Horizontal
RecyclerView, ListView, ViewPager
, etc will need your attention as well.
For Example: A HorizontalRecyclerView
can usesetStackFromEnd(true)
on it’sLayoutManager
in case of RTL layout. - If you want
Layout Direction
of aView
on runtime then useViewCompat.getLayoutDirection(view)
Note: This always returnsLTR
if called from the Constructor of a View. - If you want
Layout Direction
from aContext
then useConfiguration 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 in my app. If you found something missing or have suggestions then do comment.