Problem with text alignment in a chat bubble layout

Hi,

Here is a simple layout for sender’s chat messages:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="end"
    android:background="@android:color/holo_green_light"
    android:layout_margin="8dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="8dp"
        android:paddingEnd="8dp"
        android:paddingStart="8dp"
        android:text="Hello world"
        android:textAlignment="textStart"
        android:textColor="@android:color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <TextView
        android:id="@+id/date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="July 30, 2019"
        android:textColor="@android:color/black"
        android:textSize="10dp"
        android:paddingEnd="8dp"
        android:paddingStart="8dp"
        android:paddingBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/message" />

</androidx.constraintlayout.widget.ConstraintLayout>

What I need to achieve is that message text is aligned to the left (in case of left-to-right languages) but since message TextView is anchored to the end of the parent, the text appears at the right whenever the message TextView width is smaller than date TextView.

So, following are the results when the message text is “Hello world” and “Hi”. In both cases, message text is anchored to the end but the effect is apparent in case of “Hi” where the width is smaller than date:

Please suggest how to fix this!

Thanks

Off the cuff, anchor both TextView widgets to both sides of the ConstraintLayout, and use bias to determine where in horizontal space the text goes. Set the bias to 0 if you want the text to be shifted towards the start side of the available space.

Also, I really recommend that you use start/end consistently. Your layout is mixing start/end with left/right.

Good idea! It works in case of LTR languages but not in case of RTL. For example, Urdu appears like this, where it should be anchored to the right:

Would I have to change the bias programatically be checking it the text being displayed is RTL or LTR?

Also, I really recommend that you use start/end consistently. Your layout is mixing start/end with left/right.

Yeap I always use start and end. It is just that ConstraintLayout, by default, forces constraints using right and left instead of start and end.

Hmmm… if your anchors are start/end, the bias should be start/end. This is why I pointed out that you need to be consistent. If you want to support RTL, you need to stop using right/left in your layout.

Not in the code in your original question on this thread. You have app:layout_constraintRight_toRightOf in two places.

Google mentions ConstraintLayout RTL fixes in the 2.0.0 series. You might try implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta3" and see you get better bias results.

Another solution is to keep your anchors on start/end, leave the bias alone, set the width to 0dp (so the TextView fills the horizontal space), and use android:gravity="start" on the TextView widgets.

Even in this case, I would have to change the gravity to end dynamically for RTL languages.

Solved the issue as follows:

  • Used the layout approach as suggested by u above.

  • Used Bidi class to dynamically change the bias to 0.0 in case of LTR and 1.0 in case of RTL as follows:

      Bidi bidi = new Bidi(message.getText(), Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
      ConstraintSet constraintSet = new ConstraintSet();
      constraintSet.clone(clTextContainer);
      if (bidi.baseIsLeftToRight()) {
          constraintSet.setHorizontalBias(R.id.message, 0.0f);
      } else {
          constraintSet.setHorizontalBias(R.id.message, 1.0f);
      }
      constraintSet.applyTo(clTextContainer);
    

clTextContainer is the ConstraintLayout to which the TextView is anchored.

It works perfectly for both LTR and RTL languages.

Thanks for all the help!

No, because the meaning of “end” is tied to language direction.

If I set layout_width of both TextView to 0dp, both disappear probably because the ConstraintLayout width is set to wrap_content. If I set layout_width of only message TextView to 0dp and keep that of date to wrap_content, width of the whole layout is somehow set to the width of date TextView. If text in message TextView is large, it gets wrapped as shown below:

Or am I doing something wrong?

Ah, right, I forgot about that. Sorry!