Android 输入话题简单实现

74 阅读1分钟

需求要用到类似于抖音的#话题输入功能,简单记录一下~ 代码比较简单,仅实现了话题文本的颜色渲染,有其他需求直接加代码即可

实现效果:

WechatIMG8.jpeg

代码:


import android.content.Context
import android.text.Editable
import android.text.Spannable
import android.text.SpannableString
import android.text.TextWatcher
import android.text.style.ForegroundColorSpan
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.content.ContextCompat
class TopicEditText(context: Context, attrs: AttributeSet) : AppCompatEditText(context, attrs) {

    private val topicRegex = "#[\p{L}0-9_]+".toRegex() // 匹配话题的正则表达式
    private val topicColor = ContextCompat.getColor(context, R.color.theme) // 话题的主题色
    private var handlingTopic = false // 是否正在处理话题文本的标志位

    init {
        // 监听文本变化
        addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (!handlingTopic) {
                    handlingTopic = true
                    handleTopicText(s, start, count)
                    handlingTopic = false
                }
            }

            override fun afterTextChanged(s: Editable?) {}
        })
    }

    private fun handleTopicText(s: CharSequence?, start: Int, count: Int) {
        s ?: return
        val end = start + count
        val matcher = topicRegex.toPattern().matcher(s)
        while (matcher.find()) {
            val topicStart = matcher.start()
            val topicEnd = matcher.end()
            if (topicStart < end && topicEnd > start) {
                // 匹配到话题
                val span = ForegroundColorSpan(topicColor)
                val spannable = SpannableString(s)
                spannable.setSpan(span, topicStart, topicEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
                setText(spannable)
                setSelection(end) // 保持光标位置不变
                break
            }
        }
    }

}