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
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
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)
}
}