How to hashtag value in different colour in EditText?

前端 未结 2 1877
我寻月下人不归
我寻月下人不归 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 19:57

    Hope this solution will help..!

    I used this solution it is very useful! like adding the textWatcher interface over your editText and listening to textChange and finding out if the word starts with a hashTag then call the Change The color method on that word! it has some flaws but those are ignorable see this simple one here.

    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);
    }
    
    0 讨论(0)
  • 2020-12-11 20:07

    Kotlin

    Complete solution with custom attributes

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

    This is how you can enable tagging for the 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 "/>
    

    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<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)
            }
        }
    
    0 讨论(0)
提交回复
热议问题