如何循环遍历 Android 中的 SpannedString 或 SpannableString 中的跨度
How to loop through the spans in a SpannedString or SpannableString in Android
如果我有SpannedString
(或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);
我将如何遍历结果 String
的跨度?
按顺序循环跨度
您可以使用 getSpans
获取 Spanned
或 Spannable
String
中的跨度数组。但是,仅循环 getSpans
结果将 not necessarily give them to you in order. To get them in order you can use nextSpanTransition
.
这是一个 SpannedString
的例子,就像问题中的例子一样。 (SpannableString
的效果相同。)绿线显示跨度转换的位置。文本默认为黑色。
代码找到下一个跨度转换,然后获取当前范围内的所有跨度。
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);
}
输出:
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
感谢 this code 的想法。
跨度类型
通常在遍历跨度时,您会选择特定类型的跨度。例如,如果你想删除所有前景颜色范围,你可以执行以下操作:
// get spans
ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);
// loop through spans
for (ForegroundColorSpan span : spans) {
spannableString.removeSpan(span);
}
请注意,这不适用于 SpannedString
,因为 SpannedString
中的跨度不可变(参见 this answer)。
如果您想获取任何类型的所有跨度,您可以将类型设置为 Object.class
。
Object[] spans = spannableString.getSpans(0, spannableString.length(), Object.class);
如果您想要影响字符级别外观的所有跨度,您可以使用 CharacterStyle.class
。如果在循环中你想进一步限制属于 MetricAffectingSpan
的跨度,你可以这样做。
CharacterStyle[] spans = spannableString.getSpans(0, spannableString.length(), CharacterStyle.class);
for (CharacterStyle span : spans) {
if (span instanceof MetricAffectingSpan) {
// do something
}
}
这里是跨度类型的一般层次分解。它可能不完整。阅读 Spans, a Powerful Concept 了解更多信息。
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
如果我有SpannedString
(或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);
我将如何遍历结果 String
的跨度?
按顺序循环跨度
您可以使用 getSpans
获取 Spanned
或 Spannable
String
中的跨度数组。但是,仅循环 getSpans
结果将 not necessarily give them to you in order. To get them in order you can use nextSpanTransition
.
这是一个 SpannedString
的例子,就像问题中的例子一样。 (SpannableString
的效果相同。)绿线显示跨度转换的位置。文本默认为黑色。
代码找到下一个跨度转换,然后获取当前范围内的所有跨度。
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);
}
输出:
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
感谢 this code 的想法。
跨度类型
通常在遍历跨度时,您会选择特定类型的跨度。例如,如果你想删除所有前景颜色范围,你可以执行以下操作:
// get spans
ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);
// loop through spans
for (ForegroundColorSpan span : spans) {
spannableString.removeSpan(span);
}
请注意,这不适用于 SpannedString
,因为 SpannedString
中的跨度不可变(参见 this answer)。
如果您想获取任何类型的所有跨度,您可以将类型设置为 Object.class
。
Object[] spans = spannableString.getSpans(0, spannableString.length(), Object.class);
如果您想要影响字符级别外观的所有跨度,您可以使用 CharacterStyle.class
。如果在循环中你想进一步限制属于 MetricAffectingSpan
的跨度,你可以这样做。
CharacterStyle[] spans = spannableString.getSpans(0, spannableString.length(), CharacterStyle.class);
for (CharacterStyle span : spans) {
if (span instanceof MetricAffectingSpan) {
// do something
}
}
这里是跨度类型的一般层次分解。它可能不完整。阅读 Spans, a Powerful Concept 了解更多信息。
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