我正在尝试解决的问题如下:我正在使用TextView
并且我正在使用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 );
}
}
文本被截断,不显示“...”。
答案 0 :(得分:13)
我意识到这是一个非常古老的帖子,但看到它仍然没有答案,我今天也遇到了这个问题,我想我会发布一个解决方案。希望它能帮助将来的某个人。
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);
}
}
});
答案 1 :(得分:9)
遇到同样的问题,以下似乎对我有用:
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);
<\ n>在xml中,textView设置了android:multiLine
,android:ellipsize="end"
和android:singleLine="false
;
答案 2 :(得分:6)
你是对的,在xml或代码中声明的ellipsize不适用于spannable文本。
但是,通过一些调查,你可以自己进行椭圆机化:
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);
}
}
答案 3 :(得分:4)
通过使用反射来解决这个问题,这可能是一个小技巧。在阅读AOSP的源代码之后,在TextView.java中,DynamicLayout只包含一个名为sStaticLayout的静态字段成员,它由新的StaticLayout(null)构成,没有任何参数,包括maxLines。
因此,doEllipsis总是假的,因为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();
}
}
}
}
问题解决了!
答案 4 :(得分:1)
这是Android框架中的一个已知问题:https://code.google.com/p/android/issues/detail?id=67186
答案 5 :(得分:1)
简单易用的解决方案
这是我的代码 - &gt;
<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**);
答案 6 :(得分:0)
https://github.com/lsjwzh/FastTextView 对此有一个干净的解决方案。 你应该首先包装你的跨越字符串, 然后覆盖getSpans,getSpanStart,getSpanEnd ...... https://github.com/lsjwzh/FastTextView/blob/master/widget.FastTextView/src/main/java/android/text/EllipsisSpannedContainer.java
第207行告诉你如何使用。 https://github.com/lsjwzh/FastTextView/blob/master/widget.FastTextView/src/main/java/com/lsjwzh/widget/text/FastTextView.java
您也可以使用FastTextView而不是Android TextView
答案 7 :(得分:0)
另一种解决方案是覆盖onDraw
中的TextView
。以下建议的解决方案,不使用任何反射技术。因此,万一任何成员变量命名发生更改,将来都不应中断。
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
public class EllipsizeTextView extends TextView {
private static final String THREE_DOTS = "...";
private static final int THREE_DOTS_LENGTH = THREE_DOTS.length();
private volatile boolean enableEllipsizeWorkaround = false;
private SpannableStringBuilder spannableStringBuilder;
public EllipsizeTextView(Context context) {
super(context);
}
public EllipsizeTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public EllipsizeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public EllipsizeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setEnableEllipsizeWorkaround(boolean enableEllipsizeWorkaround) {
this.enableEllipsizeWorkaround = enableEllipsizeWorkaround;
}
// https://stackoverflow.com/questions/14691511/textview-using-spannable-ellipsize-doesnt-work
// https://blog.csdn.net/htyxz8802/article/details/50387950
@Override
protected void onDraw(Canvas canvas) {
if (enableEllipsizeWorkaround && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
final Layout layout = getLayout();
if (layout.getLineCount() >= getMaxLines()) {
CharSequence charSequence = getText();
int lastCharDown = layout.getLineVisibleEnd(getMaxLines()-1);
if (lastCharDown >= THREE_DOTS_LENGTH && charSequence.length() > lastCharDown) {
if (spannableStringBuilder == null) {
spannableStringBuilder = new SpannableStringBuilder();
} else {
spannableStringBuilder.clear();
}
spannableStringBuilder.append(charSequence.subSequence(0, lastCharDown - THREE_DOTS_LENGTH)).append(THREE_DOTS);
setText(spannableStringBuilder);
}
}
}
super.onDraw(canvas);
}
}
答案 8 :(得分:0)
对于单行情况, android:maxLines 不起作用,但是 android:singleLine 可以。
答案 9 :(得分:0)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (maxLength < 0) {
Layout layout = getLayout();
if (layout.getLineCount() > getMaxLines()) {
maxLength = layout.getLineVisibleEnd(getMaxLines() - 1) - 1;
setSpannableString();
}
}
}
“ setSpannableString()”显示如下:
private void setSpannableString() {
// ShowString is real visible string. FullString is original string which
// is useful when caching and calculating.
String showString = fullString;
if (maxLength > 0) {
showString = fullString.substring(0, maxLength) + THREE_DOTS;
}
SpannableStringBuilder builder = new SpannableStringBuilder(showString);
for (int i = 0; i < mHighLightColor.size(); i++) {
String highLightString = mHighLightString.get(i);
int color = mHighLightColor.get(i);
int start = fullString.indexOf(highLightString);
int end = Math.min(start + highLightString.length(), showString.length());
if (mClickableSpanList.get(i) != null) {
builder.setSpan(mClickableSpanList.get(i), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
setMovementMethod(LinkMovementMethod.getInstance());
}
builder.setSpan(new ColorBoldSpan(color), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
setText(builder, BufferType.SPANNABLE);
}
答案 10 :(得分:-1)