How to remove a part of Spannable

108 views Asked by At

In my android app user can change text foreground and background colors by selecting text, everything works fine, but if user created red foreground for text Hello World, and wants to remove red foreground in the World word, code removes the whole sentence background, if there's a way to do it, please, help me, here is the function:

private fun changeTextForegroundColor(

        @ColorInt foregroundColor: Int?,

        startPosition: Int,

        endPosition: Int

    ) {

        val resultText: Spannable = bindingContent.contentEditText.text.toSpannable()

        //Get foreground spans and remove them.

        val spans: Array<ForegroundColorSpan> = resultText.getSpans(

                startPosition, endPosition,

                ForegroundColorSpan::class.java)

        repeat(spans.count()) {

            resultText.removeSpan(spans[it])

        }

        

        // If foregroundColor == null, then just remove the span, what we do above

        if (foregroundColor != null) {

            resultText.setSpan(

                    ForegroundColorSpan(foregroundColor),

                    startPosition,

                    endPosition,

                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

            

        }

        bindingContent.contentEditText.setText(resultText)

        

    }

I tried not to remove, but to replace the foreground color with white(my text color) but it causes lags in my app, so I need to remove a word World, without removing the Hello word foreground in my span.

2

There are 2 answers

0
MrRuslan On BEST ANSWER

Finally, I wrote code that as I guess can resolve my problem, here I remove spans if span within selection (It won't remove span which range outside of selection), then check if color is null, then set color to white, else to another one. This code helps to to avoid issue when one span was painted over another one:

private fun changeTextForegroundColor( @ColorInt foregroundColor: Int?, startPosition: Int, endPosition: Int) {
    val resultText: Spannable =
        noteBinding.contentActivityInclude.contentEditText.text?.toSpannable() ?: return
    
    val spans: Array<ForegroundColorSpan> = resultText.getSpans(
            startPosition, endPosition,
            ForegroundColorSpan::class.java)
    spans.forEach {
        val selectedSpanStart = resultText.getSpanStart(it)
        val selectedSpanEnd = resultText.getSpanEnd(it)
        if (selectedSpanStart >= startPosition && selectedSpanEnd <= endPosition) {
            
            resultText.removeSpan(it)
            
        }
        
    }
    if (foregroundColor == null) {
        resultText.setSpan(
                ForegroundColorSpan(Color.WHITE),
                startPosition,
                endPosition,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    } else {
        resultText.setSpan(
                ForegroundColorSpan(foregroundColor),
                startPosition,
                endPosition,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        
    }
    
    noteBinding.contentActivityInclude.contentEditText.setText(resultText)
    
}
0
Cheticamp On

Make sure that you are using integer colors and not color ids in your code. You, of course, could use the color ids but you will have to make the conversion to a color integer. The following demonstrates this.

val newColor =
    ResourcesCompat.getColor(resources, android.R.color.holo_blue_light, null)
changeTextForegroundColor(newColor, 0, 5)

Then in changeTextForgroundColor()

// If foregroundColor == null, then just remove the span, what we do above
if (foregroundColor != null) {
    resultText.setSpan(
        ForegroundColorSpan(foregroundColor),
        startPosition,
        endPosition,
        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
    )
}

enter image description here