Android Spannableを使った文字装飾のオプション

※本記事はQiitaに投稿していた記事のexportです
元投稿日時: 2018/7/16

SpannableStringBuilder を使って文字を装飾する際に、setSpanで与えるflagsのそれぞれの挙動をまとめます。

setSpan の定義

public void setSpan (Object what, int start, int end, int flags)

Mark the specified range of text with the specified object. The flags determine how the span will behave when text is inserted at the start or end of the span's range.

flagsはテキストを挿入するときにしか意味をなさないようです。 色をつけただけの例と、前後に"*"を挿入した例を貼ります。

f:id:Gateau:20200328103316p:plain

class SetSpanActivity : AppCompatActivity() {

    companion object {
        fun createIntent(context: Context): Intent = Intent(context, SetSpanActivity::class.java)
    }

    private val binding: ActivitySetSpanBinding by lazy {
        DataBindingUtil.setContentView<ActivitySetSpanBinding>(this, R.layout.activity_set_span)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var decorateText = "SPAN"

        binding.textViewDecorateEE.highlight(Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, decorateText)
        binding.textViewDecorateEI.highlight(Spannable.SPAN_EXCLUSIVE_INCLUSIVE, decorateText)
        binding.textViewDecorateIE.highlight(Spannable.SPAN_INCLUSIVE_EXCLUSIVE, decorateText)
        binding.textViewDecorateII.highlight(Spannable.SPAN_INCLUSIVE_INCLUSIVE, decorateText)

        binding.textViewInsertEE.highlight(Spannable.SPAN_EXCLUSIVE_EXCLUSIVE, decorateText, "*")
        binding.textViewInsertEI.highlight(Spannable.SPAN_EXCLUSIVE_INCLUSIVE, decorateText, "*")
        binding.textViewInsertIE.highlight(Spannable.SPAN_INCLUSIVE_EXCLUSIVE, decorateText, "*")
        binding.textViewInsertII.highlight(Spannable.SPAN_INCLUSIVE_INCLUSIVE, decorateText, "*")
    }

    private fun TextView.highlight(range: Int, decorateText: String, mark: String = "") {
        val originalText = text.toString()
        val start = originalText.indexOf(decorateText)
        val end = start + decorateText.length

        val colorSpan = ForegroundColorSpan(ContextCompat.getColor(context, android.R.color.holo_red_light))
        val builder = SpannableStringBuilder(originalText).apply {
            setSpan(colorSpan, start, end, range)
        }

        text = if (mark.isBlank()) {
            builder
        } else {
            builder.apply {
                insert(end, mark) // 文字位置がずれるので後ろから設定
                insert(start, mark)
            }
        }
    }
}