Ensure spans are accounted for when measuring text.

This commit is contained in:
Alex Hart
2026-02-06 12:52:44 -04:00
committed by Greyson Parrelli
parent 6e92ff5096
commit fae4ca91bd

View File

@@ -17,6 +17,7 @@ import android.text.TextDirectionHeuristic;
import android.text.TextDirectionHeuristics; import android.text.TextDirectionHeuristics;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.TransformationMethod; import android.text.method.TransformationMethod;
import android.text.TextPaint;
import android.text.style.CharacterStyle; import android.text.style.CharacterStyle;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue; import android.util.TypedValue;
@@ -490,7 +491,7 @@ public class EmojiTextView extends AppCompatTextView {
int overflowEnd = getLayout().getLineEnd(maxLines); int overflowEnd = getLayout().getLineEnd(maxLines);
CharSequence overflow = new SpannableString(getText().subSequence(overflowStart, overflowEnd).toString()); CharSequence overflow = new SpannableString(getText().subSequence(overflowStart, overflowEnd).toString());
float adjust = overflowText != null ? getPaint().measureText(overflowText, 0, overflowText.length()) : 0f; float adjust = overflowText != null ? measureWithSpans(overflowText) : 0f;
CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth() - adjust, TextUtils.TruncateAt.END); CharSequence ellipsized = TextUtils.ellipsize(overflow, getPaint(), getWidth() - adjust, TextUtils.TruncateAt.END);
SpannableStringBuilder newContent = new SpannableStringBuilder(); SpannableStringBuilder newContent = new SpannableStringBuilder();
@@ -526,6 +527,21 @@ public class EmojiTextView extends AppCompatTextView {
} }
} }
/**
* Measures the width of the given text, applying any {@link CharacterStyle} spans to the paint
* so that typeface changes (e.g. bold) are reflected in the measurement.
*/
private float measureWithSpans(@NonNull CharSequence text) {
TextPaint measurePaint = new TextPaint(getPaint());
if (text instanceof Spanned) {
CharacterStyle[] spans = ((Spanned) text).getSpans(0, text.length(), CharacterStyle.class);
for (CharacterStyle span : spans) {
span.updateDrawState(measurePaint);
}
}
return measurePaint.measureText(text, 0, text.length());
}
/** Get text but truncated to maxLength, adjusts for end mentions and converts style spans to be exclusive on start and end. */ /** Get text but truncated to maxLength, adjusts for end mentions and converts style spans to be exclusive on start and end. */
private SpannableString getText(int maxLength) { private SpannableString getText(int maxLength) {
SpannableString shortenedText = new SpannableString(getText().subSequence(0, maxLength)); SpannableString shortenedText = new SpannableString(getText().subSequence(0, maxLength));