RTEditor/src/main/java/com/onegravity/rteditor/effects/CharacterEffect.java
public void applyToSelection(RTEditText editor, V value) {
        Selection selection = getSelection(editor);
        // SPAN_INCLUSIVE_INCLUSIVE is default for empty spans
        int flags = selection.isEmpty() ? Spanned.SPAN_INCLUSIVE_INCLUSIVE : Spanned.SPAN_EXCLUSIVE_INCLUSIVE;

        Spannable str = editor.getText();

        for (RTSpan<V> span : getSpans(str, selection, SpanCollectMode.SPAN_FLAGS)) {
            boolean sameSpan = span.getValue().equals(value);
            int spanStart = str.getSpanStart(span);
            if (spanStart < selection.start()) {
                // process preceding spans
                if (sameSpan) {
                    // we have a preceding span --> use SPAN_EXCLUSIVE_INCLUSIVE instead of SPAN_INCLUSIVE_INCLUSIVE
                    flags = Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
                    selection.offset(selection.start() - spanStart, 0);
                } else {
                    str.setSpan(newSpan(span.getValue()), spanStart, selection.start(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
            int spanEnd = str.getSpanEnd(span);
            if (spanEnd > selection.end()) {
                // process succeeding spans
                if (sameSpan) {
                    selection.offset(0, spanEnd - selection.end());
                } else {
                    str.setSpan(newSpan(span.getValue()), selection.end(), spanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
                }
            }
            str.removeSpan(span);
        }

        if (value != null) {
            RTSpan<V> newSpan = newSpan(value);
            if (newSpan != null) {
                str.setSpan(newSpan, selection.start(), selection.end(), flags);
            }
        }
    }
public void applyToSelection(RTEditText editor, V value) {
        Selection selection = getSelection(editor);
        // SPAN_INCLUSIVE_INCLUSIVE is default for empty spans
        int flags = selection.isEmpty() ? Spanned.SPAN_INCLUSIVE_INCLUSIVE : Spanned.SPAN_EXCLUSIVE_INCLUSIVE;

        Spannable str = editor.getText();

        for (RTSpan<V> span : getSpans(str, selection, SpanCollectMode.SPAN_FLAGS)) {
            boolean sameSpan = span.getValue().equals(value);
            int spanStart = str.getSpanStart(span);
            if (spanStart < selection.start()) {
                // process preceding spans
                if (sameSpan) {
                    // we have a preceding span --> use SPAN_EXCLUSIVE_INCLUSIVE instead of SPAN_INCLUSIVE_INCLUSIVE
                    flags = Spanned.SPAN_EXCLUSIVE_INCLUSIVE;
                    selection.offset(selection.start() - spanStart, 0);
                } else {
                    str.setSpan(newSpan(span.getValue()), spanStart, selection.start(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
            int spanEnd = str.getSpanEnd(span);
            if (spanEnd > selection.end()) {
                // process succeeding spans
                if (sameSpan) {
                    selection.offset(0, spanEnd - selection.end());
                } else {
                    str.setSpan(newSpan(span.getValue()), selection.end(), spanEnd, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
                }
            }
            str.removeSpan(span);
        }

        if (value != null) {
            RTSpan<V> newSpan = newSpan(value);
            if (newSpan != null) {
                str.setSpan(newSpan, selection.start(), selection.end(), flags);
            }
        }
    }
Apply this effect to the selection.
If value is Null then the effect will be removed from the current selection.

@param editor The editor to apply the effect to (current selection)
@param value  The value to apply (depends on the Effect)