如何在 EditText 中以不同颜色标记值?

How to hashtag value in different colour in EditText?

我正在 EditText 中写一些文本,当我写 "#data" 时,它的颜色应该改变,但不会改变我该怎么做。请检查下面的EditText我用过的

<EditText
         android:id="@+id/et_simple"
         android:layout_height="wrap_content"
         android:layout_width="match_parent">
</EditText>

希望此解决方案对您有所帮助...!

我用过这个解决方案,非常有用!比如在 editText 上添加 textWatcher 接口并监听 textChange 并找出单词是否以 hashTag 开头,然后调用该单词的 Change The color 方法!它有一些缺陷,但可以忽略不计,请在此处查看这个简单的缺陷。

Spannable mspanable;
int hashTagIsComing = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);



    final EditText edtTxtMine = (EditText) findViewById(R.id.editText1);

    mspanable = edtTxtMine.getText();

    edtTxtMine.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            String startChar = null;

            try{
                startChar = Character.toString(s.charAt(start));
                Log.i(getClass().getSimpleName(), "CHARACTER OF NEW WORD: " + startChar);
            }
            catch(Exception ex){
                startChar = "";
            }

                if (startChar.equals("#")) {
                     changeTheColor(s.toString().substring(start), start, start + count);
                     hashTagIsComing++;
                }

                if(startChar.equals(" ")){
                    hashTagIsComing = 0;
                }

                if(hashTagIsComing != 0) {
                    changeTheColor(s.toString().substring(start), start, start + count);
                    hashTagIsComing++;
                }
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub

        }
    });



}


private void changeTheColor(String s, int start, int end) {
    mspanable.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.color)), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}

科特林

具有自定义属性的完整解决方案

    <declare-styleable name="EditTextView">
        <attr name="enableTagging" format="boolean"/>
    </declare-styleable>
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)
        }
    }
}

这是为 EditText 启用标记的方法

<com.example.xyz.util.editbox.EditTextView
        xmlns:custom="http://schemas.android.com/apk/res-auto"
        android:id="@+id/et"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"

        custom:enableTagging="true"

        tools:textAppearance="@style/TextAppearance.AppCompat.Moment.Date"
        tools:text="Name the "/>

编辑:

以上机制在您删除任何字符或您的编辑文本是多行的情况下不起作用,下面应该起作用:

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

或者如果你像我一样喜欢扩展,这可以重构为

fun CharSequence.getTagIndices(toIndex:Int = 0):Pair<Int, Int>? {
    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)
        }
    }

您可以轻松地使用 CodeView 库来突出主题标签、电子邮件或数据格式

CodeView mCodeView = findViewById(R.id.codeView);
Pattern hashTagPattern = Pattern.compile("#[a-zA-z0-9]+");
mCodeView.addSyntaxPattern(hashTagPattern, Color.BLUE);

你需要初始化它并为hashtag设置一个带有颜色的模式然后你可以在运行时改变颜色,结果会像这样

图书馆link:https://github.com/AmrDeveloper/codeview

以上别人说的方法我都试过了。一切正常。但它工作正常

mSpannable = binding?.captionLayout?.etInput?.text

    binding?.captionLayout?.etInput?.addTextChangedListener(object : TextWatcher{
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
        override fun onTextChanged(short_text: CharSequence, start: Int, before: Int, count: Int) {

            val text = binding?.captionLayout?.etInput?.text.toString()
            var last_index = 0
            text.trim().split(Regex("\s+")).forEach {
             
                if (it.isNotEmpty() && it[0] == '#'){
                    //here you can style the hashtag text(I have made it bold and black)
                    val boldSpan = StyleSpan(Typeface
                        .BOLD)
                    val foregroundSpan = ForegroundColorSpan(ContextCompat.getColor(requireActivity(), R.color.black))
                    mSpannable?.setSpan(foregroundSpan, text.indexOf(it,startIndex = last_index), text.indexOf(it,startIndex = last_index)+it.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
                    mSpannable?.setSpan(boldSpan, text.indexOf(it,startIndex = last_index), text.indexOf(it,startIndex = last_index)+it.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)

                }

                last_index+=it.length-1

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