Проблема с окрашиванием текста в EditText
Есть вот такой код для окраски текста:
public class MainActivity extends AppCompatActivity {
private EditText mEditText;
private static final Map<Character, Integer> COLORS_MAP = new HashMap<>();
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// просто какие-то цвета
COLORS_MAP.put('a', Color.RED);
COLORS_MAP.put('b', Color.GREEN);
COLORS_MAP.put('c', Color.BLUE);
COLORS_MAP.put('d', Color.MAGENTA);
COLORS_MAP.put('e', Color.BLUE / 2 + Color.GREEN / 2 - Color.RED / 4);
COLORS_MAP.put('f', Color.LTGRAY + Color.YELLOW);
COLORS_MAP.put('g', Color.BLUE + Color.CYAN);
COLORS_MAP.put('h', Color.YELLOW);
COLORS_MAP.put('i', Color.DKGRAY + Color.MAGENTA / 16);
COLORS_MAP.put('j', Color.RED + Color.GREEN);
COLORS_MAP.put('k', Color.CYAN);
mEditText = findViewById(R.id.editText);
mEditText.addTextChangedListener(new TextWatcher() {
boolean lock = false;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (lock)
return;
if (before == count)
return;
SpannableStringBuilder sb = new SpannableStringBuilder(s);
for (int i = 0; i < sb.length(); i++) {
Integer color = pickColorByChar(sb.charAt(i));
if (color == null)
color = mEditText.getTextColors().getDefaultColor();
sb.setSpan(new ForegroundColorSpan(color), i, i + 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
lock = true;
mEditText.setText(sb);
lock = false;
mEditText.setSelection(start + count);
}
@Override
public void afterTextChanged(Editable s) {}
});
}
@Nullable
public Integer pickColorByChar(char c) {
return COLORS_MAP.get(c);
}
}
Мне в нём не нравится производительность, а именно то, что при каждом вводе символа приходится пробегать текст заново и для каждого символа проставлять цвета.
Почему это надо делать? Потому что следующий код работает не так, как надо:
public class MainActivity extends AppCompatActivity {
private EditText mEditText;
private static final Map<Character, Integer> COLORS_MAP = new HashMap<>();
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// просто какие-то цвета
COLORS_MAP.put('a', Color.RED);
COLORS_MAP.put('b', Color.GREEN);
COLORS_MAP.put('c', Color.BLUE);
COLORS_MAP.put('d', Color.MAGENTA);
COLORS_MAP.put('e', Color.BLUE / 2 + Color.GREEN / 2 - Color.RED / 4);
COLORS_MAP.put('f', Color.LTGRAY + Color.YELLOW);
COLORS_MAP.put('g', Color.BLUE + Color.CYAN);
COLORS_MAP.put('h', Color.YELLOW);
COLORS_MAP.put('i', Color.DKGRAY + Color.MAGENTA / 16);
COLORS_MAP.put('j', Color.RED + Color.GREEN);
COLORS_MAP.put('k', Color.CYAN);
mEditText = findViewById(R.id.editText);
mEditText.addTextChangedListener(new TextWatcher() {
boolean lock = false;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (lock)
return;
if (count < before)
return;
int curPos = start + before;
char curChar = s.charAt(curPos);
SpannableStringBuilder sb = new SpannableStringBuilder(s);
Integer color = pickColorByChar(curChar);
if (color == null)
color = mEditText.getTextColors().getDefaultColor();
sb.setSpan(new ForegroundColorSpan(color), curPos, curPos + 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
lock = true;
mEditText.setText(sb);
lock = false;
mEditText.setSelection(start + count);
}
@Override
public void afterTextChanged(Editable s) {}
});
}
@Nullable
public Integer pickColorByChar(char c) {
return COLORS_MAP.get(c);
}
}
А именно: при чередовании двух каких-либо символов, все символы в одном слове, написанные до текущего, окрашиваются в цвет предыдущего символа.
Почему так происходит?
