Два TextViews бок о бок, только один для эллипсизации?

Я хочу, чтобы два элемента TextView отображались бок о бок (в элементе списка), один был выровнен слева, один - вправо. Что-то вроде:

|<TextView>               <TextView>|

(| представляют крайности экрана)

Тем не менее, TextView слева может содержать слишком длинный контент, который будет помещаться на экране. В этом случае я хочу, чтобы он был эллипсисом, но все же отображал все правое TextView. Что-то вроде:

|This is a lot of conte...<TextView>|

У меня было множество попыток, используя как LinearLayout, так и RelativeLayout, и единственным решением, которое я придумал, является использование RelativeLayout и добавление marginRight влево TextView big достаточно, чтобы очистить право TextView. Как вы можете себе представить, это не оптимально.

Есть ли другие решения?

Конечное, LinearLayout решение:

<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:orientation="horizontal"
    >
    <TextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_weight="1"
        android:ellipsize="end"
        android:inputType="text"
        />
    <TextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_weight="0"
        android:layout_gravity="right"
        android:inputType="text"
        />
</LinearLayout>

Старый, TableLayout решение:

<TableLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:stretchColumns="1"
    android:shrinkColumns="0"
    >
    <TableRow>
        <TextView android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:singleLine="true"
            />
        <TextView android:id="@+id/date"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:singleLine="true"
            android:ellipsize="none"
            android:gravity="right"
            />
    </TableRow>
</TableLayout>

Ответ 1

Используйте TableLayout и поместите оба TextView в строку таблицы, попробуйте. Я не пробовал

Ответ 2

Просто идея, почему бы вам не объявить сначала в макете xml текстовое изображение справа и установить его ширину в качестве содержимого обложки, android:layout_alignParentRight="true" и android:gravity="right". Затем объявите текстовое поле слева, установите его ширину как заполняющий родительский элемент, android:layout__toLeftOf= {идентификатор текстового поля справа} с RelativeView в качестве корневого представления.

Объявив сначала правильное текстовое представление, его требуемая ширина будет сначала вычислена и займет вид, а текстовое изображение слева займет оставшееся пространство представления.

Я все еще не пробовал это, хотя это может дать вам некоторую идею.

[Обновление]

Я попытался создать макет ресурса xml... и он как-то работает...

<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <TextView 
    android:id="@+id/right"
    android:layout_alignParentRight="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="right"
    android:text="right"
    >
  </TextView>
  <TextView 
    android:id="@+id/left"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@id/right"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:lines="1"
    android:singleLine="true"
    android:maxLines="1"
    android:text="too looooooooooong ofskgjo sdogj sdkogjdfgds dskjgdsko jgleft"
    >
  </TextView>
</RelativeLayout>

Ответ 3

Ответ LinearLayout работал у меня с этой же проблемой. Добавлено как отдельный ответ, потому что было непонятно, что делали и не работали для искателя.

Одно отличие. TableLayout был менее идеальным для меня, потому что у меня было две строки данных, и я хотел, чтобы нижняя строка вела себя так, как описывает этот вопрос, и верхнюю строку для охвата области. На этот вопрос был дан ответ в другом вопросе SO: Colspan в TableLayout, но LinearLayout был проще.

Хотя получение ширины справа меня немного. Я включил настройку андроидного линта с использованием ширины 0dp для элемента масштабирования для производительности.

<LinearLayout
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:orientation="horizontal"
    >
    <TextView
        android:layout_height="wrap_content"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:ellipsize="end"
        android:inputType="text"
        />
    <TextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_weight="0"
        android:layout_gravity="right"
        android:inputType="text"
        />
</LinearLayout>

Ответ 4

Есть много ответов на этот и практически эквивалентные, повторяющиеся вопросы о SO. Предлагаемые подходы обычно работают, как бы то ни было. Поместите его в LinearLayout, оберните все в дополнительный RelativeLayout, используйте TableLayout; все они, похоже, решают его для более простой компоновки, но если вам нужны эти два TextView внутри чего-то более сложного или один и тот же макет будет повторно использоваться, например, с помощью RecyclerView, все будет очень быстро сломаться.

Единственное решение, которое я нашел, которое действительно работает все время, независимо от того, какой большой макет вы его вложили, - это настраиваемый макет. Он очень прост в реализации, и, будучи таким худым, как это возможно, он будет поддерживать макет достаточно плоский, его легко поддерживать, поэтому в конечном итоге я считаю это лучшим решением проблемы.

public class TwoTextLayout extends ViewGroup {

  public TwoTextLayout(Context context) {
    super(context);
  }

  public TwoTextLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public TwoTextLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    final int count = getChildCount();
    if (count != 2)
      throw new IllegalStateException("TwoTextLayout needs exactly two children");

    int childLeft = this.getPaddingLeft();
    int childTop = this.getPaddingTop();
    int childRight = this.getMeasuredWidth() - this.getPaddingRight();
    int childBottom = this.getMeasuredHeight() - this.getPaddingBottom();
    int childWidth = childRight - childLeft;
    int childHeight = childBottom - childTop;

    View text1View = getChildAt(0);
    text1View.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
    int text1Width = text1View.getMeasuredWidth();
    int text1Height = text1View.getMeasuredHeight();

    View text2View = getChildAt(1);
    text2View.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST));
    int text2Width = text2View.getMeasuredWidth();
    int text2Height = text2View.getMeasuredHeight();

    if (text1Width + text2Width > childRight)
      text1Width = childRight - text2Width;

    text1View.layout(childLeft, childTop, childLeft + text1Width, childTop + text1Height);
    text2View.layout(childLeft + text1Width, childTop, childLeft + text1Width + text2Width, childTop + text2Height);
  }
}

Реализация не может быть проще, она просто измеряет два текста (или любые другие дочерние представления на самом деле), и если их общая ширина превышает ширину макета, уменьшает ширину первого вида.

И если вам нужны изменения, например. для выравнивания второго текста к базовой линии первого, вы также можете легко решить эту проблему:

text2View.layout(childLeft + text1Width, childTop + text1Height - text2Height, childLeft + text1Width + text2Width, childTop + text1Height);

Или любое другое решение, например, сокращение второго представления по отношению к первому, выравнивание вправо и т.д.

Ответ 5

Почему бы вам не поместить левое поле в правый TextView? Я использую этот подход для

|<TextView>       <ImageButton>|

и он работает.

Ответ 6

Решение с ConstraintLayout

<?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="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp">

    <TextView
        android:id="@+id/leftText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:maxLines="1"
        app:layout_constraintEnd_toStartOf="@id/rightText"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="This is a lot of content that should be cut" />

    <TextView
        android:id="@+id/rightText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Right text" />

</androidx.constraintlayout.widget.ConstraintLayout>

enter image description here