2016-08-09 7 views
9

Я выкладываю 3 вида горизонтально на экране (фиксированное изображение и 2 однострочных текста: leftTextView и rightTextView), и я пытаюсь получить rightTextView, чтобы обнять leftTextView, но в том случае, если ширина обеих меток будет превышать размер экрана, обрезайте leftTextiew.Приоритет уклонения Android TextView или сопротивление сжатию

Пример требуемой функциональности:

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

Что происходит на самом деле:

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

В настоящее время, если размер обоих текстовых взглядов превышает ширину вида по rightTextView заканчивает тем, что сплющенные вниз, чтобы сделать хотя я установил android:ellipsize="end" на leftTextView.

Есть ли способ сделать leftTextView «приоритетом усечения», который говорит, что он должен усекать, если это приведет к тому, что другие виды не подходят? Или с другой стороны, могу ли я установить rightTextView на «сопротивление сжатию», чтобы он не скручивался, чтобы освободить место для leftTextView? Вот пример моего 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> 

Вещи, которые я пробовал:

  1. В leftTextView, добавьте toStartOf/toLeftOfrightTextView (сбой приложения)
  2. Вместо того, совместив rightTextView до конца/справа от leftTextView, переверните его и выровняйте leftTextView в начало/влево от rightTextView. Это приводит к тому, что rightTextView привязывается к концу экрана, а не прямо справа от leftTextView. Пример того, как это заканчивает тем, что:

    |img|leftText     |rightText|| 
    |img|leftTextMedium   |rightText|| 
    |img|leftTextTooLongSoTrunc...|rightText|| 
    
  3. Даже если я устанавливаю android:minWidth="25dp" только для обеспечения по меньшей мере, часть из rightTextView видно (что я не хочу делать, потому что этот текст длина переменная) он все еще заканчивает сжатие ширины, чтобы освободить место для leftTextView.

  4. Ответ на вопрос Emanuel Moecklin, я попробовал обернуть в LinearLayout и установить вес на leftTextView. Результат был визуально идентичен тому, что я пробовал в # 2.
+0

В моей защите дубликата маркировки, что другой вопрос не имеет ответа в то время, я спросил мой. Кроме того, его название ужасно, и, вероятно, поэтому я не понимал, что он существует в первую очередь. – Stonz2

ответ

6

Вы можете архивировать этот макет с помощью атрибута TableLayout и shrinkColumns.

<?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

+0

Можно ли это сделать для вертикальных макетов? Мне нужно, чтобы элементы в TableRow были выровнены по вертикали и заданы андроид: shrinkColumns = "0", чтобы сжать первый вид. – Vlad

1

Вот что я делаю:

<?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> 

андроид: layout_weight = "1" делает "трюк" здесь. Документация не совсем понятно, на этом, хотя:

Например, если есть три текстовых поля и две из них объявить вес 1, в то время как другой не дается никакого веса, то третье текстовое поле без веса не будет расти и займет только область, требуемую его содержание.

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

Он подробно не по делу, в котором нет места для заполнения, но не хватает места для всех представлений. Одна интерпретация упомянутой части документации заключалась бы в том, что поле без веса (в этом случае rightTextView) будет занимать область, требуемую ее содержимым, в то время как поле с весом (в этом случае LeftTextView) будет «расти» (как в отрицательном рост), и это именно то, что происходит.

+0

Хотя вес позволяет «отрицательный рост», о котором вы упоминаете, он также расширяет поле для заполнения ширины, когда это не нужно. Это заканчивается тем, что 'rightTextView' прикрепляется к праву/концу родительского представления. Функционально он выглядит так же, как и в №2 того, что я пытался в вопросе. – Stonz2

1

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

Основная идея того, что здесь происходит, - это подклассическое LinearLayout и в проходе onMeasure, я проверяю, чтобы правый вид имел возможность занимать как можно больше места. Обратите внимание, что я должен пересмотреть правильный вид, а не просто получить измеренную ширину, потому что linearlayout не даст ему достаточно места. Как только у вас будет столько места, которое занимает правильный вид, проверьте, занимает ли средний вид (называемый leftView ... sorry) больше места, чем вы хотите. Если да, просто дайте ему пространство, которое осталось.

Основываясь на ваших потребностях в том, что он находится в RecyclerView ... Я знаю, что вы сказали, что хотите получить чистое xml-решение, но вы получите лучшую производительность, если вы справитесь с ним в коде как xml 1. Может быть невозможно и 2. потребует больше вычислений, чем просто делать это непосредственно.

public class CustomLinearLayout extends LinearLayout { 

private View child0; 
private TextView leftView, rightView; 
public CustomLinearLayout(Context context) { 
    super(context); 
} 

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

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

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
    if (rightView == null) { 
     child0 = getChildAt(0); 
     leftView = (TextView)getChildAt(1); 
     rightView = (TextView) getChildAt(2); 
    } 

    int spec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST); 
    rightView.measure(spec, spec); 

    int remaining = getMeasuredWidth() - child0.getMeasuredWidth() - rightView.getMeasuredWidth(); 
    if (leftView.getMeasuredWidth() > remaining) { 
     int specW = MeasureSpec.makeMeasureSpec(remaining, MeasureSpec.AT_MOST); 
     int specH = MeasureSpec.makeMeasureSpec(leftView.getMeasuredHeight(), MeasureSpec.EXACTLY); 
     leftView.measure(specW, specH); 
    } 
} 

расположение XML

<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:id="@+id/layout" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" 
tools:context="com.example.joshua.myapplication.MainActivity"> 

<com.example.joshua.myapplication.CustomLinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal"> 
    <ImageView 
     android:layout_width="30dp" 
     android:layout_height="30dp" 
     android:background="#FF0000"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:ellipsize="end" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Left View With Really Really Long Text That should fill the screen"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Right View" 
     /> 
</com.example.joshua.myapplication.CustomLinearLayout> 

<com.example.joshua.myapplication.CustomLinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:orientation="horizontal" 
    android:layout_marginTop="20dp"> 
    <ImageView 
     android:layout_width="30dp" 
     android:layout_height="30dp" 
     android:background="#FF0000"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:ellipsize="end" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Left View with short text"/> 
    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:maxLines="1" 
     android:textSize="18sp" 
     android:text="My Right View" 
     /> 
</com.example.joshua.myapplication.CustomLinearLayout> 
</LinearLayout> 

enter image description here

+0

Спасибо за ответ. Я дал ему завихрение, и он отлично работает, но подход nshmura также работает, но он чисто в XML и не зависит от подкласса. – Stonz2

0

Просто используйте android:maxWidth свойство левой TextView. Таким образом, ваше левое поле никогда не превысит этого предела. и всегда будет место для вашего правильного просмотра.

<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" 
     android:src="@drawable/ic_launcher" /> 

    <TextView 
     android:id="@+id/leftTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerVertical="true" 
     android:layout_toEndOf="@+id/fixedWidthImage" 
     android:layout_toRightOf="@+id/fixedWidthImage" 
     android:ellipsize="end" 
     android:lines="1" 
     android:maxWidth="250dp" 
     android:text="This is a Long left Text which never ends and You'll be tired after reading this long stuff.. blah blah... " /> 

    <TextView 
     android:id="@+id/rightTextView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerVertical="true" 
     android:layout_toEndOf="@+id/leftTextView" 
     android:layout_toRightOf="@+id/leftTextView" 
     android:ellipsize="end" 
     android:lines="1" 
     android:text="Right Text" /> 

</RelativeLayout> 

Preview of layout

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

Кроме того, для отображения длинного текста в одной строке android:ellipsize="marquee" является хорошим вариантом. Поскольку он будет прокручивать ваш горизонтальный вид. Но не забудьте написать этот код textView.setSelected(true) в своем коде, чтобы он работал. Detail

+0

С Android, имеющим такое большое различие в размерах экрана (плюс портрет и пейзаж), фиксированная ширина определенно не является желательным. – Stonz2

+0

Я уже говорил, что это сработает, когда вы знаете некоторый размер фиксированной ширины. В противном случае вы можете сделать это программно, как предложил @whizzle. –