30
votes

I have a simple TextView which should have android:gravity="left" for ltr system locales and android:gravity="right" for rtl system locales.

The obvious choice would be: android:gravity="start" but then e.g. english text will always be left-aligned and hebrew right-aligned.

Here is how it looks with android:gravity="start":

LTR locale:

|          לורם|   // incorrect
|test           |  // correct

RTL locale:

|          לורם|  // correct
|test           |  // incorrect

it's supposed to look like that:

LTR locale:

|לורם           |  
|test            | 

RTL locale:

|          לורם|  
|           test| 

Is it possible to do that without using a layout-ldrtl folder with a modified xml file? This would complicate development a lot because I would have to edit a lot of layout files twice...

edit: a solution for API 17+ is enough. I wrote system locale, but actually I'm allowing the user to change the app language like that:

Configuration configuration = context.getResources().getConfiguration();
configuration.setLayoutDirection(selectedLocale);
configuration.locale = selectedLocale;
context.getResources().updateConfiguration(configuration, context.getResources().getDisplayMetrics());

so it would be great if this locale would be considered for the rtl <-> ltr choice.

4
English text is rendered left to right i think with gravity start - Bhargav
yes, exactly that is my problem. Is there a way of forcing RTL when the RTL locale is set? - agrajag
have tried adding the textdirection attribute? but its only for api 17+ i think - Bhargav
@Bhargav good advice. If I set it to android:textDirection="locale" its aligned regarding the system locale, but not the "app locale", see my edit... Sorry for the confusion, I was trying to simplify... - agrajag
another problem I noticed with textDirection is that if you use android:ellipsize and force RTL textDirection the "..." will be placed on the left side, even for english... This looks totally wrong. - agrajag

4 Answers

70
votes

I had this problem too, you can use these properties with the TextView

android:textDirection="locale"
android:textAlignment="gravity"

or just add it to the Base App Theme in styles.xml`

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:textColorPrimary">@android:color/white</item>
    <item name="android:textColorSecondary">@android:color/white</item>
    <item name="colorButtonNormal">@color/colorAccent</item>
    <item name="android:textAlignment">gravity</item>
    <item name="android:textDirection">locale</item>
    </style>`

That worked for me.

39
votes
android:layout_width="match_parent"    
android:textAlignment="viewStart"

If text view is stretched to parent width, there is no need to change the gravity of the element. Just align the text to the view start, the text will move to LTR or RTL position, independent of the text content (hebrew or western).

2
votes

You probably need a special extended TextView class for that:

public class LocaleAwareTextView extends TextView {
    public LocaleAwareTextView(Context context) {
        super(context);
        setGravity(getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? Gravity.RIGHT : Gravity.LEFT);
    }
    public LocaleAwareTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setGravity(getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? Gravity.RIGHT : Gravity.LEFT);
    }

    public LocaleAwareTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setGravity(getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? Gravity.RIGHT : Gravity.LEFT);
    }

}

... and use this class in your layouts. If you want to switch the locale and all orientations on the fly, you will need to reload your layouts.

2
votes

I'm using this solution now, I would prefer a simple xml solution, but this seems minimal so far:

if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
  if (DynamicLanguage.getLayoutDirection(getContext()) == View.LAYOUT_DIRECTION_RTL) {
    this.textView.setGravity(Gravity.RIGHT);
  } else {
    this.textView.setGravity(Gravity.LEFT);
  }
}