Ellipsize только раздел в TextView - PullRequest
6 голосов
/ 12 июля 2010

Мне было интересно, можно ли сокращать только часть строки в TextView.Я хотел бы сделать что-то вроде этого:

Element with short title (X)
Element with a very lo...(X)

Заголовок должен быть эллиптическим, но X всегда должен быть виденВ моем случае невозможно использовать более одного TextView.Как вы думаете, есть простой способ сделать это?

Спасибо!

Ответы [ 2 ]

12 голосов
/ 03 сентября 2012

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

Вот реализация TextView с расширенным управлением многоточием. Как это работает, используя интерфейс Spanned Android. Он определяет перечисление, которое вы можете использовать, чтобы пометить определенный раздел текста, который вы хотите, чтобы он был эллиптическим, если это необходимо.

Ограничения:

  • Не поддерживает многоточие в середине. Это должно быть легко добавить, если это действительно необходимо (я не сделал).
  • Этот класс всегда отображает текст в одну строку, поскольку он поддерживает только одну строку текста. Другие могут расширить его, если это необходимо (но это гораздо сложнее).

Вот пример использования:

FooActivity.java

class FooActivity extends Activity {

  /**
   * You can do this however you'd like, this example uses this simple
   * helper function to create a text span tagged for ellipsizing
   */
  CharSequence ellipsizeText(String text) {
    SpannableString s = new SpannableString(text);
    s.setSpan(TrimmedTextView.EllipsizeRange.ELLIPSIS_AT_END, 0, s.length(),
      Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
    return s;
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.foo_layout);
    TextView textView = (TextView) findViewById(R.id.textView4);
    SpannableStringBuilder text = new SpannableStringBuilder();
    text.append(ellipsizeText("This is a long string of text which has important information "));
    text.append("AT THE END");
    textView.setText(text);
  }
}

Рез / макеты / foo_layout.xml

<com.example.text.TrimmedTextView
  android:id="@+id/textView4"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"/>

Вот и все

Вот пример результата:

screenshot_of_example

Реализация

package com.example.text;

import android.content.Context;
import android.text.Editable;
import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class TrimmedTextView extends TextView {
  public static enum EllipsizeRange {
    ELLIPSIS_AT_START, ELLIPSIS_AT_END;
  }

  private CharSequence originalText;
  private SpannableStringBuilder builder = new SpannableStringBuilder();

  /**
   * This allows the cached value of the original unmodified text to be
   * invalidated whenever set externally.
   */
  private final TextWatcher textCacheInvalidator = new TextWatcher() {
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
      originalText = null;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
  };

  public TrimmedTextView(Context context) {
    this(context, null, 0);
  }

  public TrimmedTextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public TrimmedTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    addTextChangedListener(textCacheInvalidator);
    Log.v("TEXT", "Set!");
  }

  /**
   * Make sure we return the original unmodified text value if it's been
   * custom-ellipsized by us.
   */
  public CharSequence getText() {
    if (originalText == null) {
      return super.getText();
    }
    return originalText;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    Layout layout = getLayout();
    CharSequence text = layout.getText();
    if (text instanceof Spanned) {
      Spanned spanned = (Spanned) text;
      int ellipsisStart;
      int ellipsisEnd;
      TruncateAt where = null;
      ellipsisStart = spanned.getSpanStart(EllipsizeRange.ELLIPSIS_AT_START);
      if (ellipsisStart >= 0) {
        where = TruncateAt.START;
        ellipsisEnd = spanned.getSpanEnd(EllipsizeRange.ELLIPSIS_AT_START);
      } else {
        ellipsisStart = spanned.getSpanStart(EllipsizeRange.ELLIPSIS_AT_END);
        if (ellipsisStart >= 0) {
          where = TruncateAt.END;
          ellipsisEnd = spanned.getSpanEnd(EllipsizeRange.ELLIPSIS_AT_END);
        } else {
          // No EllipsisRange spans in this text
          return;
        }
      }

      Log.v("TEXT", "ellipsisStart: " + ellipsisStart);
      Log.v("TEXT", "ellipsisEnd:   " + ellipsisEnd);
      Log.v("TEXT", "where:         " + where);

      builder.clear();
      builder.append(text, 0, ellipsisStart).append(text, ellipsisEnd, text.length());
      float consumed = Layout.getDesiredWidth(builder, layout.getPaint());
      CharSequence ellipsisText = text.subSequence(ellipsisStart, ellipsisEnd);
      CharSequence ellipsizedText = TextUtils.ellipsize(ellipsisText, layout.getPaint(),
          layout.getWidth() - consumed, where);
      if (ellipsizedText.length() < ellipsisText.length()) {
        builder.clear();
        builder.append(text, 0, ellipsisStart).append(ellipsizedText)
            .append(text, ellipsisEnd, text.length());
        setText(builder);
        originalText = text;
        requestLayout();
        invalidate();
      }
    }
  }
}
1 голос
/ 12 июля 2010

Вы можете попробовать использовать что-то вроде этого:

myTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE);

Это может не дать вам именно то, что вы хотите, хотя, оно может сделать что-то вроде этого:

Элемент wi...title (X)

Справочная информация

TruncateAt
setEllipsize

...