Ellipsize only a section in a TextView

前端 未结 2 398
予麋鹿
予麋鹿 2021-01-05 10:28

I was wondering if it is possible to abbreviate only a portion of a string in a TextView. What I would like to do is something like this:

Element with short          


        
相关标签:
2条回答
  • 2021-01-05 10:48

    You can try using something like this:

    myTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
    

    It might not give you exactly what you want though, it may do something like this:

    Element wi...title (X)

    Reference Info

    TruncateAt
    setEllipsize

    0 讨论(0)
  • 2021-01-05 10:50

    I really needed a clean solution for a project so after searching around and not finding any solutions I felt I liked, I took some time to write this up.

    Here is an implementation of a TextView with enhanced ellipsis control. The way it works is by using Android's Spanned interface. It defines an enum you can use to tag the specific section of text you'd like to be ellipsized if needed.

    Limitations:

    • Does not support ellipsis at MIDDLE. This should be easy to add if it's really needed (I didn't).
    • This class will always render the text onto one line, as it only supports a single line of text. Others are welcome to extend it if that's needed (but it's a far harder problem).

    Here's a sample of the usage:

    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);
      }
    }
    

    res/layouts/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"/>
    

    That's it

    Here's an example of the result:

    screenshot_of_example

    The Implementation

    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();
          }
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题