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

Posted

技术标签:

【中文标题】如何在 EditText 中以不同颜色标记值?【英文标题】:How to hashtag value in different colour in EditText? 【发布时间】:2019-01-01 04:53:16 【问题描述】:

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

<EditText
         android:id="@+id/et_simple"
         android:layout_
         android:layout_>
</EditText>

【问题讨论】:

观看textWatcher兄弟的lib。 @salman developer.android.com/reference/android/text/TextWatcher 【参考方案1】:

希望这个解决方案会有所帮助..!

我使用了这个解决方案,非常有用!就像在你的 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);

【讨论】:

当您更改光标位置并开始随机添加或删除文本或主题标签时,它会开始做一些奇怪的事情,它最终会以更改的颜色结束写入所有内容,无论是否有主题标签。【参考方案2】:

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

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

您需要初始化它并使用colou为主题标签设置一个模式,然后您可以在运行时更改颜色,结果将是这样的

库链接:https://github.com/AmrDeveloper/codeview

【讨论】:

【参考方案3】:

科特林

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

    <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_
        android:layout_
        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)
        
    

【讨论】:

EditTextView 没有获得焦点。当用户点击它时光标会闪烁,然后消失。【参考方案4】:

我已经尝试了其他人提到的所有上述方法。没有任何工作正常。但它工作正常

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

【讨论】:

以上是关于如何在 EditText 中以不同颜色标记值?的主要内容,如果未能解决你的问题,请参考以下文章

标记指定颜色

如何在 Windows 命令行中以不同的颜色回显 [关闭]

如何在谷歌地图中显示不同颜色的最新标记

如何将我在 EditText 框中键入的数据添加到数组中以在另一个活动中列出?

为 EditText 中的文本分配文本颜色

Echarts 地图 省份的颜色自定义如何设置?