Blog Infos
Author
Published
Topics
, ,
Author
Published

Posted by: Cengiz Toru

Hello Android followers. Today I’ll write all my RTL ( Right to Left ) support design experiences on Android. I hope this article will save your time. Take your tea/coffee/water and let’s start.

Almost all scripts in the world are written from Left to Right. But some script like Arabic is written from Right to Left. So for the best user experience, we should support Right to Left design, too.

When a UI changed from LTR to RTL (or vice versa) it’s named “mirroring”. If you looking for a design guidelines about which UI components should be mirroring and which UI components shouldn’t mirroring, you can check out material.io.

Some Important Points From The material.io Article

  • Numbers such as those on a clock and phone numbers are shouldn’t be mirrored.
  • LTR text shouldn’t be displayed in reverse order. E.g. if a number in LTR is 123456 in RTL must be 123456, too. Don’t reverse it. The direction of such texts must be LTR.
  • The texts untranslated to RTL language shouldn’t be mirrored (even if it’s parts of a phrase)
  • Charts and graphs shouldn’t be mirrored.
  • Icons that don’t communicate direction such as a camera ?, search ?, keyboard ⌨️, headset ?, call ? are shouldn’t be mirrored
  • Icons containing numbers should be localized for other languages that use different numerals.
  • You shouldn’t mirror slashes on images. Because the LTR slashes describe an off state for both LTR and RTL languages. E.g. No Parking
  • Media playback buttons and media progress indicator shouldn’t be mirrored if they refer to the direction of tape being played

The Android OS has native RTL design support since SDK 17 version. Keep in mind.

First of all, you must add android:supportsRtl="true" to the <application>element in your manifest file for your app to supporting RTL design.

Trick: If your app supports multiple languages and if you have code snippet like config.setLayoutDirection(Locale.US) you must change it. Otherwise, your app will not support the RTL design. You can change the code line like below.

After that, replace your app’s all left/right layout properties start/end with their equivalents. If you must support versions earlier than SDK 17 you should use both left/right and start/end properties in the same view. When you do this The Android OS is gonna handle your almost all views layout mirroring automatically. In my opinion, set your minSdkVersion is 21 so Android 5. Because almost all phones sdk version is over than 21 in 2021. In this article, I assume your minSdkVersion is 19 and higher.

You can feel terrible when you think about replacing all left/right properties to start/end. Stop feeling like that, calm down and keep reading. I have a trick for you.

Trick: Android Studio just has a tool for replacing all properties with their RTL equalivents. For doing this follow these steps.

Click right on res folder. After that hold to the cursor on Refactor finally click Add Right-to-Left (RTL) Support. When you did these a window will appear like below.

On this window unmark Update AndroidManifest.xml and mark Replace Left/Right Properties with Start/End properties and Run it. After the operations finished a window will appear like below.

It shows you which layouts will be refactoring. If you want to refactor only your project layouts you can exclude other layout files from came 3rd party libraries.

Select layout files which you don’t want to refactor, click right and exclude all. When you did these your layout files will be like below.

After that click Do Refactor. And now your all layout properties changed with their equivalents. Check your local changes and Run Project?. You can see your almost all layouts will be supporting RTL design.

By only these changes your app maybe can’t fully support RTL design. For a fully supported RTL design, you should pay attention to the below sections.

Supporting Directional Resources

Android’s RTL engine reverses layout direction but doesn’t reverse resources (so drawables) automatically. So if we have a directional image we must reverse it manually.

You know android projects resources directories have some qualifiers as -night-v24-v21-xxhdpi-ar . Like these also has -ldrtl qualifier meaning “layout direction right-to-left” for resources working on RTL languages.

Supporting Images, Icons 

Suppose we have a shopping cart image like the above A option. It must be shown as the B option in RTL design. Normally we place A image as res/drawable/ic_cart.png or res/drawable/ic_cart.xml on our project. For supporting this image on RTL design firstly prepare a new directory named as res/drawable-ldrtl. After that get your right to left supported image (B option) having the same name as LTR image and place it in the drawable-ldrtl directory. The Android OS will render the right file when loading your interfaces. It will support LTR design and RTL design both.

(Also for using some resource files in LTR design you can prepare files with -ldrtl qualifier)

Trick: If you are using icons as Vector Assets (files with .xml extension) you don’t need a new directory with -ldrtl qualifier. When you add android:autoMirrored=”true” line in vector tag, your icon gonna has RTL support automatically. (This work SDK 19 and higher version.) So you don’t need to store 2 files in your project. In this way, your apk size will be smaller. And when you want to change your icon it will be enough to change only one file.

Supporting Animations

Animations that use X-axis don’t work well on RTL design. You can prepare res\transition-ldrtl or res\anim-ldrtl directories and placing RTL design-supported animation files in these directories. Make sure LTR animation file and RTL animation file names are the same. For example, res\anim\slide_out_right.xml and res\anim-ldrtl\slide_out_right.xml

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

, ,

Building State Holders in Compose with Molecule: A New Approach to Reusable UI Components

Are your ViewModels exponentially growing out of control as they manage the state for each of your Composables? This talk introduces Molecule, a new library for creating state holders in Jetpack Compose.
Watch Video

Building State Holders in Compose with Molecule: A New Approach to Reusable UI Components

Jack Adams
Senion Android Engineer
Trainline

Building State Holders in Compose with Molecule: A New Approach to Reusable UI Components

Jack Adams
Senion Android Engin ...
Trainline

Building State Holders in Compose with Molecule: A New Approach to Reusable UI Components

Jack Adams
Senion Android Engineer
Trainline

Jobs

Supporting Views

Supporting RecyclerView

Officially supported. You don’t need to do anything in addition to the above. How wonderful, isn’t it?

Supporting ViewPagers

If you use ViewPager2 in your project also you can skip this section. Because ViewPager2 officially supports RTL design. Otherwise, If you use ViewPager you can support RTL design in 2 ways; rotating some views and migrating to ViewPager2.

Rotating Views

You need to add a new value as locale_viewpager_rotation=0 to integers.xml. After that prepare another integers.xml file under the values-ldrtl folder. Add locale_viewpager_rotation =180 value in this xml file. Finally android:rotationY=”@integer/locale_viewpager_rotation” code snippet to your viewpager (You can also use this method for any view). In this way, your viewpagers will be rotated on RTL design. For fully supporting may need to rotate the content of viewpager items, too. And indicators, too.

I tried this method. It isn’t an efficient solution so in my opinion just migrate to ViewPager 2.

Migrating ViewPager2

ViewPager2 built on RecyclerView so it has RTL support officially. So for the best solution migrate your ViewPager adapter to ViewPager2 adapter. And get benefits of ViewPager2.

Also if you use TabLayout with ViewPager you must migrate it to ViewPager2 implementation, too. You can use

TabLayoutMediator(mTabLayout, mViewPager) { tab, position ->
tab.text = it[position].title
}.attach()

code snippet instead of mTabLayout.setupWithViewPager(mViewPager) .

Supporting TextViews

TextView officially supports RTL design. If you use start-end properties instead of left-right it works well in RTL design. So when you setted an RTL script text to textview, text will start from right automatically.

But if in RTL mode you set an LTR script text, textView’s text will start left like below (Even if you replaced left/right to start/end).

If you don’t want to this, you can add android:textDirection=”locale”attribute to your textViews. I recommend this because the screen becomes more fluid. When you did this your textViews shown as below. Even if textView’s text LTR script, it will start from right. Of course, you can combine this attribute with styles in styles.xml.

Finally

In some cases, if you be obligated to setting textView direction to LTR and if you want to LTR scripts shown on right in RTL design, you can set

if(isCurrentLanguageRTL) {
textView.gravity = Gravity.END
}
view raw SomeView.kt hosted with ❤ by GitHub

programmatically.

Supporting EditTexts

EditText officially supports RTL design. If you use start-end properties instead of left-right it works well in RTL design. So when you write an RTL script text to edittext, the edittext’s text will start from right automatically.

But when the app is in RTL mode if you write an LTR script text, editText’s text will start left like as TextView. If you don’t want to this and even in LTR scripts if you want to edditext’s text start from right you can try below options

  • First of all, be careful for adding android:gravity property.
  • If your edittext is inside TextInputLayout you can add android:textDirection=”locale” attribute to TextInputLayout. It will works like below

If android:textDirection=”locale” not works you can try adding android:textAlignment=”viewStart” attribute to TextInputEditText

  • If you have simple edittext you can add android:textDirection=”locale” attribute to your EditText. If android:textDirection=”locale” not works you can try adding android:textAlignment=”viewStart” attribute to EditText.
  • If you want to fix the cursor to the far right of the edittext you can use below code snippet
if (isCurrentLanguageRTL) {
etEmail.doOnTextChanged { text, start, before, count ->
etEmail.setSelection(0)
}
}
view raw SomeView.kt hosted with ❤ by GitHub

Supporting WebViews

When you loading an HTML data/block to webView if it hasn’t got RTL support you can manipulate it by below code snippet. So it will support RTL design.

willLoadHtmlData = if(isCurrentLanguageRTL) <html dir=\"rtl\"><body> $mainHtmlData </body></html> else $mainHtmlData

Supporting Custom Layouts for Specific Scripts

If you want to add a specific version of the layout that is designed for only Arabic text, your directory structure becomes the following:

res/layout/main.xml This layout file is loaded by default.

res/layout-ar/main.xml This layout file is loaded with Arabic text.

res/layout-ldrtl/main.xml This layout file is loaded only for non-Arabic languages that use an RTL text direction.

Some Code Snippets which maybe you’ll need

  • If you use Gravity.LEFT/RIGHT you should replace to Gravity.START/END.
  • If you want to learn the layout direction of a view you can obtain it by view.layoutDirection code snippet
  • For obtaining the layout direction of a context you can use this context.resources.configuration.layoutDirection code snippet.
  • For changing layoutDirection you can use view.layoutDirection = View.LAYOUT_DIRECTION_RTL code snippet
  • For checking layout direction is you can use a condition like below
val layoutDirection = context.resources.configuration.layoutDirection
val viewLayoutDirection = view.layoutDirection
if (layoutDirection == View.LAYOUT_DIRECTION_RTL){
//do stuff
}
view raw View.kt hosted with ❤ by GitHub
  • For obtaining text direction of a view you can do this with view.textDirection. So you can set like view.textDirection = view.textDirection = View.TEXT_DIRECTION_RTL
  • For layout direction for specific locale you can use TextUtils. getLayoutDirectionFromLocale (locale)
  • If you have a custom view and if you need a callback when RTL properties changed you can override the below function
val layoutDirection = context.resources.configuration.layoutDirection
val viewLayoutDirection = view.layoutDirection
if (layoutDirection == View.LAYOUT_DIRECTION_RTL){
//do stuff
}
view raw View.kt hosted with ❤ by GitHub

Conclusion

For fully supported RTL design in your app, briefly you can follow these steps

  • Replace your app’s all left/right layout properties with start/end which are their equivalents.
  • If you use ViewPager, just migrate ViewPager2.
  • Set text direction “locale” for your text views
  • Add autoMirrored = true in your icons which need to mirroring in RTL design.

Thank you for reading. If you think the article is useful please clap ? and share so more people benefit.

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
In this part of the series, we will plan our first screen in Jetpack…
READ MORE
blog
We’ll be selecting a time whenever a user presses a number key. Following points…
READ MORE
blog
With JCenter sunsetted, distributing public Kotlin Multiplatform libraries now often relies on Maven Central…
READ MORE
blog
Jetpack Compose has revolutionized Android development by providing a modern, declarative approach to building…
READ MORE
Menu