How to hashtag value in different colour in EditText?

前端 未结 2 1885
我寻月下人不归
我寻月下人不归 2020-12-11 19:23

I am writing some text in EditText when i write \"#data\" its colour should be changed but doesn\'t change how can i do. Please check the below

2条回答
  •  误落风尘
    2020-12-11 20:07

    Kotlin

    Complete solution with custom attributes

        
            
        
    
    class EditTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatEditText(context, attrs, defStyleAttr) {
        private var hashtagindex = -1
        private var enableTagging:Boolean = false
            set(value) {
                field = value
                invalidate()
                requestLayout()
            }
    
        init {
            context.theme.obtainStyledAttributes(
                attrs,
                R.styleable.EditTextView, 0, 0).apply {
                    try {
                        enableTagging = getBoolean(R.styleable.EditTextView_enableTagging, false)
                    } finally {
                        recycle()
                    }
            }
        }
    
    
        override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
            text?.let { handleTagging(text, start, lengthBefore, lengthAfter) }
        }
    
        private fun handleTagging(text: CharSequence, start: Int, lengthBefore: Int, lengthAfter: Int) {
            if (!enableTagging || text.length <= start) return
            if (text[start] == '#') hashtagindex = start
            if (text[start] == ' ') hashtagindex = -1
            // If hashtag then color the work
            if (hashtagindex >= 0) {
                val spannableString = getText()
                val foregroundSpan = ForegroundColorSpan(ContextCompat.getColor(context, R.color.colorPrimary))
                spannableString?.setSpan(foregroundSpan, hashtagindex, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
        }
    }
    

    This is how you can enable tagging for the EditText

    
    

    EDIT :

    The above mechanism does not work in case you delete any char or your edit text is multiline, the below should work :

     private fun handleTagging(text: CharSequence, start: Int, lengthBefore: Int, lengthAfter: Int) {
        if (!enableTagging || text.length <= start) return
    
        val formattedText = text.substring(0, start).trim();
        val lastWord =  formattedText.split(Regex("\\s+")).last()
        val tagIndex = if (lastWord.isNotEmpty() && lastWord[0] == '#') formattedText.lastIndexOf('#') else -1
    
        if (tagIndex >= 0) {
            val foregroundSpan = ForegroundColorSpan(ContextCompat.getColor(context, R.color.colorPrimary))
            getText()?.setSpan(foregroundSpan, tagIndex, start + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        }
    }
    

    Or if you like extensions as I do, this can be refactored as

    fun CharSequence.getTagIndices(toIndex:Int = 0):Pair? {
        val formattedText = substring(0, toIndex).trim()
        val lastWord =  formattedText.split(Regex("\\s+")).last().trim()
        if (!lastWord.startsWith('#') || lastWord.endsWith('#')) return null
        val startIndex = formattedText.lastIndexOf('#')
        val endIndex = formattedText.length - 1
        if (startIndex < 0 || endIndex < 0) return null
        return Pair(startIndex, endIndex)
    }
    
     private fun handleTagging(text: CharSequence, start: Int, lengthBefore: Int, lengthAfter: Int) {
            if (!enableTagging || text.length <= start) return
    
            text.getTagIndices(start + 1)?.let {
                val foregroundSpan = ForegroundColorSpan(ContextCompat.getColor(context, R.color.colorPrimary))
                getText()?.setSpan(foregroundSpan, it.first, it.second + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
        }
    

提交回复
热议问题