Как использовать расширяемые строки в addTextChangedListener для изменения цвета подстроки EditText?

#java #android #android-edittext #spannablestring #addtextchangedlistener

#java #Android #android-edittext #spannablestring #addtextchangedlistener

Вопрос:

Я пытаюсь реализовать что-то похожее на редактор кода, где ключевые слова автоматически выделяются. У меня будет массив строк, и я хочу изменить цвет и шрифт строки EditText, когда пользователь вводит текст, и он соответствует строке из массива строк. Я использую addTextChangeListener, но текст всего EditText изменяется. Я хочу, чтобы было выделено только совпадающее слово.Я понимаю, что мне нужно использовать расширяемые строки, но происходит сбой кода. Кто-нибудь может мне помочь с правильным использованием расширяемых строк с помощью addTextChangedListener()? Вот мой код:

 editText.addTextChangedListener(new TextWatcher() {
            private SpannableString spanString;
            private ForegroundColorSpan span;
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                spanString = new SpannableString(s);
                span = new ForegroundColorSpan(Color.YELLOW);
                spanString.setSpan(span, start, start   count, 0);
            }
            @Override
            public void afterTextChanged(Editable s) {
                int beginIdx = spanString.getSpanStart(s);
                int endIdx = spanString.getSpanEnd(s);

                if(s.subSequence(beginIdx, endIdx).equals("for"))
                {
                        editText.setText(spanString, EditText.BufferType.SPANNABLE);
                }
                spanString.removeSpan(span);
                span = null;
                spanString = null;
            }
        });
 

Комментарии:

1. Помогло бы показать ошибку actula

2. Он выдает исключение нулевого указателя

Ответ №1:

ms1996 Я знаю, что вы пытаетесь создать IDE. Чтобы выделить синтаксис кодов codes, вы должны использовать расширяемую строку или использовать любую библиотеку, чтобы упростить ее. Кроме того, вы можете попробовать этот код :

                     I created simple code for highlight syntax in EditText. First i created a HashMap to store keywords and colors.

                    Map<String,Integer> map = new HashMap<>();
                    map.put("public",Color.CYAN);
                    map.put("void", Color.BLUE);
                    map.put("String",Color.RED);
 

Затем я добавил TextWatcher для EditText. В методе afterTextChanged я использовал следующий код для установки цветов для каждого ключевого слова,

                     ........
                    @Override
                    public void afterTextChanged(Editable editable) {
                        String string = editable.toString();
                        String[] split = string.split("\s");
                        for(int i = 0 ; i < split.length ; i  ){
                            String s = split[i];
                            if(map.containsKey(s)){
                                int index = string.indexOf(s);
                                int color = map.get(s);
                                editable.setSpan(new ForegroundColorSpan(color),
                                        index,
                                        index   s.length(),
                                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                            }

                        }
                    }
 

Комментарии:

1. Потрясающе! Это выглядит идеально. Только один незначительный сбой. Если EditText снова увидит ключ map, он не изменит цвет этого ключа. Как я должен это исправить?

2. Этот ответ очень приблизил меня к нужной мне функции. Все еще пытаюсь понять, почему оно выделяет слово только один раз. Спасибо!

3. Вы можете ознакомиться с этой статьей для получения более качественных результатов:medium.com/@hossainkhan /…

Ответ №2:

Вызывая editText.setTextColor(getResources().getColor(R.color.indigo)); , вы устанавливаете цвет для всего EditText.

Вы должны установить цвет диапазона вашего ключевого слова (в данном случае ключевого слова «for»). Для этого вы должны знать позицию ключевого слова в строке (начальный и конечный индекс ключевого слова). Тогда это можно установить следующим образом.

     editText.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
        }
        @Override
        public void afterTextChanged(Editable s) {
            if (s.toString().contains("for"))
            {
                Spannable wordToSpan = new SpannableString("for");
                wordToSpan.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.indigo), START_INDEX_OF_THE_KEYWORD_IN_THE_STRING, END_INDEX_OF_THE_KEYWORD_IN_THE_STRING, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                editText.setText(wordToSpan);
            }
        }
    });
 

Поскольку для установки диапазона требуется вызов setText, также имейте в виду, что вам необходимо защитить от бесконечного цикла…

Комментарии:

1. Поскольку afterTextChanged сообщает нам только о том, что что-то в s изменилось, а не где, как мне получить начальный idx и конечный idx, которые требуются функции setSpan?

Ответ №3:

Попробуйте это, запросите любой запрос. Вы можете изменить цвет любого текста, просто замените «для» на нужный текст и замените цвет —

 editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                String string = s.toString();

                if (string.contains("for")) {
                    //Count to change color of all the "for"
        int count = (string.length() - string.replaceAll("for", "").length())/3;

                    //You can make these global
                    int start = 0;
                    int beginIdx = 0;
                    int endIdx = 0;
                    for (int i = 0; i < count; i  ) {
                        beginIdx = string.indexOf("for", start);
                        endIdx = beginIdx   3;
                        start = endIdx;
                        if (beginIdx > 0)
                            s.setSpan(new ForegroundColorSpan(Color.GREEN),//ContextCompat.getColor(getContext(), R.color.indigo)
                                    beginIdx, endIdx, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

                    }

                }
            }
        });
 

Комментарии:

1. Это работает хорошо. Я не понял ту часть, где вы сохраняете количество для всех «для». Как я должен масштабировать это для любого ключевого слова, длина которого может быть не равна 3?

2. @ms1996 измените текст (например, «для») и разделите на количество символов в этой текстовой строке.