Как пропустить промежутки в SpannedString или SpannableString в Android

Если у меня есть SpannedString (или SpannableString) как это

введите описание изображения здесь

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?

(Я отправляю это как самостоятельный ответ, так как я узнал, как это сделать в последнее время.)

Ответ 1

Прохождение через промежутки в порядке

Вы можете использовать getSpans для получения массива пролетов в Spanned или Spannable String. Однако простое выполнение результатов getSpans будет не обязательно давать их вам в порядке. Чтобы привести их в порядок, вы можете использовать nextSpanTransition.

Вот пример с SpannedString как пример в вопросе. (A 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

Благодаря этот код для идей.

Типы пролетов

Обычно при прохождении через промежутки вы выбираете определенный тип пролета. Например, если вы хотите удалить все цветовые интервалы переднего плана, вы можете сделать следующее:

// get spans
ForegroundColorSpan[] spans = spannableString.getSpans(0, spannableString.length(), ForegroundColorSpan.class);

// loop through spans
for (ForegroundColorSpan span : spans) {
    spannableString.removeSpan(span);
}

Обратите внимание, что это не будет работать с SpannedString, потому что пробелы в SpannedString не изменяются (см. этот ответ).

Если вы хотите получить все интервалы любого типа, вы должны установить тип как 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
    }
}

Вот общее иерархическое разбиение типов span. Возможно, оно не будет полным. Подробнее читайте Spans, мощная концепция.

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