If I have a SpannedString
(or SpannableString
) like this
SpannableString spannableString = new SpannableString("Hello World!");
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(Color.YELLOW);
spannableString.setSpan(foregroundSpan, 1, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
spannableString.setSpan(backgroundSpan, 3, spannableString.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
How would I loop through the spans of the resulting String
?
Looping through the spans in order
You can use getSpans
to get an array of the spans in a Spanned
or Spannable
String
. However, just looping through the getSpans
results will not necessarily give them to you in order. To get them in order you can use nextSpanTransition
.
Here is an example with a SpannedString
like the example in the question. (A SpannableString
would work the same.) The green lines show where the span transitions are. The text is black by default.
The code finds the next span transition and then gets all the spans in the current range.
int next;
for (int i = 0; i < spannableString.length(); i = next) {
// find the next span transition
next = spannableString.nextSpanTransition(i, spannedString.length(), CharacterStyle.class);
// get all spans in this range
int numOfSpans = 0;
CharacterStyle[] spans = spannableString.getSpans(i, next, CharacterStyle.class);
for(int j = 0; j < spans.length; j++) {
numOfSpans++;
}
Log.i("TAG", "spans from " + i + " to " + next + ": " + numOfSpans);
}
Output:
spans from 0 to 1: 0
spans from 1 to 3: 1
spans from 3 to 8: 2
spans from 8 to 11: 1
spans from 11 to 12: 0
Thanks to this code for ideas.
Types of spans
Normally when looping through the spans you would choose a certain type of span. For example, if you wanted to remove all the foreground color spans, you could do the following:
// get spans
ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);
// loop through spans
for (ForegroundColorSpan span : spans) {
spannableString.removeSpan(span);
}
Note that this wouldn't work with a SpannedString
because the spans in a SpannedString
are not mutable (see this answer).
If you wanted to get all the spans of any type you would set the type as Object.class
.
Object[] spans = spannableString.getSpans(0, spannableString.length(), Object.class);
If you wanted all the spans that affect the appearance at the character level, you would use CharacterStyle.class
. If within the loop you wanted to further limit the spans to those belonging to MetricAffectingSpan
, you could do it like this.
CharacterStyle[] spans = spannableString.getSpans(0, spannableString.length(), CharacterStyle.class);
for (CharacterStyle span : spans) {
if (span instanceof MetricAffectingSpan) {
// do something
}
}
Here is a general hierarchical breakdown of the span types. It may not be complete. Read Spans, a Powerful Concept for more information.
Object
CharacterStyle
BackgroundColorSpan
ClickableSpan
URLSpan
ForegroundColorSpan
MaskFilterSpan
StrikethroughSpan
SuggestionSpan
UnderlineSpan
MetricAffectingSpan
AbsoluteSizeSpan
LocaleSpan
RelativeSizeSpan
ReplacementSpan
DynamicDrawableSpan
ImageSpan
ScaleXSpan
StyleSpan
SubscriptSpan
SuperscriptSpan
TextAppearanceSpan
TypefaceSpan
ParagraphStyle
AlignmentSpan
AlignmentSpan.Standard
BulletSpan
DrawableMarginSpan
IconMarginSpan
LeadingMarginSpan
LeadingMarginSpan.LeadingMarginSpan2
LeadingMarginSpan.Standard
LineBackgroundSpan
LineHeightSpan
LineHeightSpan.WithDensity
QuoteSpan
TabStopSpan
TabStopSpan.Standard
WrapTogetherSpan