TextView с использованием Spannable – эллипсис не работает

Проблема, которую я пытаюсь исправить, заключается в следующем: у меня есть TextView и я использую Spannable для Spannable некоторых символов жирным шрифтом. Текст должен иметь максимум 2 строки ( android:maxLines="2" ), и я хочу, чтобы текст был эллипсированным, но по какой-то причине я не могу сделать текст эллипсисом.

Вот простой код:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:maxLines="2" android:ellipsize="end" android:bufferType="spannable" android:text="@string/app_name" android:textSize="15dp"/> </LinearLayout> 

И деятельность:

 public class MyActivity extends Activity { private TextView name; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); name= (TextView) findViewById(R.id.name); name.setText("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy "); Spannable spannable = (Spannable)name.getText(); StyleSpan boldSpan = new StyleSpan( Typeface.BOLD ); spannable.setSpan( boldSpan, 10, 15, Spannable.SPAN_INCLUSIVE_INCLUSIVE ); } } 

Текст усечен, никаких «…» не отображается. Введите описание изображения здесь

Solutions Collecting From Web of "TextView с использованием Spannable – эллипсис не работает"

Имея такую ​​же проблему и, похоже, для меня работает следующее:

 Spannable wordtoSpan = new SpannableString(lorem); wordtoSpan.setSpan(new ForegroundColorSpan(0xffff0000), 0, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); wordtoSpan.setSpan(new ForegroundColorSpan(0xff00ffff), 20, 35, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(wordtoSpan); 

В xml textView имеет android:mutileLine set и android:ellipsize="end" , android:singleLine="false ;

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

 ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver(); viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { ViewTreeObserver viewTreeObserver = textView.getViewTreeObserver(); viewTreeObserver.removeOnGlobalLayoutListener(this); if (textView.getLineCount() > 5) { int endOfLastLine = textView.getLayout().getLineEnd(4); String newVal = textView.getText().subSequence(0, endOfLastLine - 3) + "..."; textView.setText(newVal); } } }); 

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

Тем не менее, с небольшим количеством расследований вы можете фактически сделать эллипсинг самостоятельно:

 private TextView name; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); name= (TextView) findViewById(R.id.name); String lorem = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy " name.setText(lorem); Spannable spannable = (Spannable)name.getText(); StyleSpan boldSpan = new StyleSpan(Typeface.BOLD); spannable.setSpan( boldSpan, 10, 15, Spannable.SPAN_INCLUSIVE_INCLUSIVE); int maxLines = 2; // in my experience, this needs to be called in code, your mileage may vary. name.setMaxLines(maxLines); // check line count.. this will actually be > than the # of visible lines // if it is long enough to be truncated if (name.getLineCount() > maxLines){ // this returns _1 past_ the index of the last character shown // on the indicated line. the lines are zero indexed, so the last // valid line is maxLines -1; int lastCharShown = name.getLayout().getLineVisibleEnd(maxLines - 1); // chop off some characters. this value is arbitrary, i chose 3 just // to be conservative. int numCharsToChop = 3; String truncatedText = lorem.substring(0, lastCharShown - numCharsToChop); // ellipsize! note ellipsis character. name.setText(truncatedText+"…"); // reapply the span, since the text has been changed. spannable.setSpan(boldSpan, 10, 15, Spannable.SPAN_INCLUSIVE_INCLUSIVE); } } 

Это известная проблема в инфраструктуре Android: https://code.google.com/p/android/issues/detail?id=67186

Это может немного обмануть, используя отражение, чтобы решить эту проблему. После чтения исходного кода AOSP в TextView.java DynamicLayout содержит только статический член поля с именем sStaticLayout и он создается новым StaticLayout (null) без каких-либо параметров, включая maxLines.

Следовательно, doEllipsis всегда будет false, поскольку mMaximumVisibleLineCount по умолчанию задает Integer.MAX_VALUE.

 boolean firstLine = (j == 0); boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount); boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd); ...... if (ellipsize != null) { // If there is only one line, then do any type of ellipsis except when it is MARQUEE // if there are multiple lines, just allow END ellipsis on the last line boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount); boolean doEllipsis = (((mMaximumVisibleLineCount == 1 && moreChars) || (firstLine && !moreChars)) && ellipsize != TextUtils.TruncateAt.MARQUEE) || (!firstLine && (currentLineIsTheLastVisibleOne || !moreChars) && ellipsize == TextUtils.TruncateAt.END); if (doEllipsis) { calculateEllipsis(start, end, widths, widthStart, ellipsisWidth, ellipsize, j, textWidth, paint, forceEllipsis); } } 

Поэтому я расширяю TextView и создаю представление с именем EllipsizeTextView

 public class EllipsizeTextView extends TextView { public EllipsizeTextView(Context context) { super(context); } public EllipsizeTextView(Context context, AttributeSet attrs) { super(context, attrs); } public EllipsizeTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); } public EllipsizeTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { StaticLayout layout = null; Field field = null; try { Field staticField = DynamicLayout.class.getDeclaredField("sStaticLayout"); staticField.setAccessible(true); layout = (StaticLayout) staticField.get(DynamicLayout.class); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } if (layout != null) { try { field = StaticLayout.class.getDeclaredField("mMaximumVisibleLineCount"); field.setAccessible(true); field.setInt(layout, getMaxLines()); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (layout != null && field != null) { try { field.setInt(layout, Integer.MAX_VALUE); } catch (IllegalAccessException e) { e.printStackTrace(); } } } 

}

задача решена!

Простое и эффективное решение

Это мой код ->

 <TextView android:id="@+id/textViewProfileContent" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="false" android:ellipsize="end" android:maxLines="3" android:textSize="14sp" android:textColor="#000000" /> SpannableStringBuilder sb = new SpannableStringBuilder(); SpannableString attrAdditional = new SpannableString(additionalText); attrAdditional.SetSpan(new StyleSpan(TypefaceStyle.Bold), 0, additionalText.Length, 0);... sb.Append(attrAdditional);... ProfileContent.SetText(sb, **TextView.BufferType.Normal**); 

результат