Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android TextView Truncation Priority or Compression Resistance [duplicate]

I'm laying out 3 views horizontally on the screen (fixed-size image and 2 single-line text views: leftTextView and rightTextView) and I'm trying to get the rightTextView to hug against the leftTextView, but in the event that the width of both labels would exceed the screen size, truncate the leftTextiew.

Example of desired functionality:

|img|leftText|rightText|                ||(end of screen)
|img|leftTextMedium|rightText|          ||
|img|leftTextTooLongSoTrunc...|rightText||

What's actually happening:

|img|leftText|rightText|                ||(end of screen)
|img|leftTextPrettyLongButNotHuge|rightT||
|img|leftTextWhichIsIncrediblyLongBlahBl||

Currently, if the size of both text views exceeds the view's width, the rightTextView ends up getting squished down to make room, even though I've set android:ellipsize="end" on the leftTextView.

Is there a way to make the leftTextView have a "truncation priority" that says it should truncate if it would cause other views to not fit? Or on the other side, can I set the rightTextView to have a "compression resistance" in order to keep it from being squished to make room for the leftTextView? Here's a sample of my XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/fixedWidthImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:id="@+id/leftTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/fixedWidthImage"
        android:layout_toRightOf="@id/fixedWidthImage"
        android:maxLines="1"
        android:textSize="18sp"
        android:ellipsize="end" />

    <TextView
        android:id="@+id/rightTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@+id/leftTextView"
        android:layout_toRightOf="@+id/leftTextView"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:maxLines="1"
        android:textSize="12sp" />

</RelativeLayout>

Things I've tried:

  1. In the leftTextView, add a toStartOf / toLeftOf the rightTextView (crashes the app)
  2. Instead of aligning the rightTextView to the end/right of the leftTextView, flip it and align the leftTextView to the start/left of the rightTextView. This results in the rightTextView being anchored to the end of the screen instead of directly to the right of the leftTextView. Example of how this ends up looking:

    |img|leftText                 |rightText||
    |img|leftTextMedium           |rightText||
    |img|leftTextTooLongSoTrunc...|rightText||
    
  3. Even if I set android:minWidth="25dp" just to ensure at least part of the rightTextView is visible (which I don't want to do because this text length is variable) it still ends up compressing the width to make room for the leftTextView.

  4. Per Emanuel Moecklin's answer, I tried wrapping in a LinearLayout and setting the weight on the leftTextView. The result was visually identical to what I tried in #2.
like image 252
Stonz2 Avatar asked Aug 09 '16 21:08

Stonz2


2 Answers

You can archive this layout by TableLayout and shrinkColumns attribute.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <!-- Row 1 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="1">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/ic_launcher"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="leftText"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>


    <!-- Row 2 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="1">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/ic_launcher"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="leftTextPrettyLongButNotHuge"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>

    <!-- Row 3 -->
    <TableLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:shrinkColumns="1">

        <TableRow
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_vertical">

            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/ic_launcher"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="end"
                    android:text="leftTextWhichIsIncrediblyLongBlahBlahBlahBlah"/>

            <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:padding="4dp"
                    android:maxLines="1"
                    android:ellipsize="none"
                    android:text="rightText"/>
        </TableRow>

    </TableLayout>

</LinearLayout>

enter image description here

like image 180
nshmura Avatar answered Oct 03 '22 19:10

nshmura


Here's what I do:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/fixedWidthImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/ic_launcher_pro" />

    <TextView
        android:id="@+id/leftTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_gravity="center_vertical|left"
        android:ellipsize="marquee"
        android:lines="1"
        android:text="This is a very long text, and now even longer" />

    <TextView
        android:id="@+id/rightTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|left"
        android:lines="1"
        android:text="This is also quite long" />

</LinearLayout>

The android:layout_weight="1" does the "trick" here. The documentation isn't quite clear on this one though:

For example, if there are three text fields and two of them declare a weight of 1, while the other is given no weight, the third text field without weight will not grow and will only occupy the area required by its content.

(https://developer.android.com/guide/topics/ui/layout/linear.html#Weight)

It doesn't elaborate on the case in which there isn't space to fill but not enough space for all views. One interpretation of the mentioned piece of documentation would be that a field without weight (the rightTextView in this case) will occupy the area required by its content while a field with weight (the leftTextView in this case) will "grow" (as in negative growth) and that's exactly what happens.

like image 31
Emanuel Moecklin Avatar answered Oct 03 '22 18:10

Emanuel Moecklin