使用 Span 在 android EditText 上突出显示语法?
Syntax highlighting on android EditText using Span?
我在 EditText
中为高亮语法创建了简单的代码。
首先,我创建了一个 HashMap
来存储关键字和颜色。
Map<String,Integer> map = new HashMap<>();
map.put("public",Color.CYAN);
map.put("void", Color.BLUE);
map.put("String",Color.RED);
然后我为 EditText
添加了一个 TextWatcher
。
在 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);
}
}
}
如果我输入不同的词,例如 "public void String",此代码可以正常工作,但是当我输入时它不起作用
同样的词,"public public public"。它只为第一个单词设置颜色。
我怎样才能完成这项工作?谢谢。
由于每次for循环后查找索引的起始位置总是相同的,所以我添加了一个startIndex来记录变化的起始位置,这里是示例代码:
public void afterTextChanged(Editable editable) {
String string = editable.toString();
String[] split = string.split("\s");
int startIndex = 0;
for(int i = 0 ; i < split.length ; i++){
String s = split[i];
if(map.containsKey(s)){
int index = string.indexOf(s, startIndex);
int color = map.get(s);
editable.setSpan(new ForegroundColorSpan(color),
index,
index + s.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
startIndex = index + s.length();
}
}
}
使用string.indexOf(s)
将获得第一次出现。您可以使用正则表达式,而不是使用关键字映射并使用 indexOf
。我很快就写了这个作为例子:
下面示例 EditText 的屏幕截图:
示例:
final EditText editText = new EditText(this);
editText.addTextChangedListener(new TextWatcher() {
ColorScheme keywords = new ColorScheme(
Pattern.compile(
"\b(package|transient|strictfp|void|char|short|int|long|double|float|const|static|volatile|byte|boolean|class|interface|native|private|protected|public|final|abstract|synchronized|enum|instanceof|assert|if|else|switch|case|default|break|goto|return|for|while|do|continue|new|throw|throws|try|catch|finally|this|super|extends|implements|import|true|false|null)\b"),
Color.CYAN
);
ColorScheme numbers = new ColorScheme(
Pattern.compile("(\b(\d*[.]?\d+)\b)"),
Color.BLUE
);
final ColorScheme[] schemes = { keywords, numbers };
@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) {
removeSpans(s, ForegroundColorSpan.class);
for (ColorScheme scheme : schemes) {
for(Matcher m = scheme.pattern.matcher(s); m.find();) {
s.setSpan(new ForegroundColorSpan(scheme.color),
m.start(),
m.end(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
void removeSpans(Editable e, Class<? extends CharacterStyle> type) {
CharacterStyle[] spans = e.getSpans(0, e.length(), type);
for (CharacterStyle span : spans) {
e.removeSpan(span);
}
}
class ColorScheme {
final Pattern pattern;
final int color;
ColorScheme(Pattern pattern, int color) {
this.pattern = pattern;
this.color = color;
}
}
});
由于一些答案已经被接受,我想回答我遇到的一个问题,当时我按下退格键,单词从 "String" 变为 "Strin" 或 "Srn"(中间的退格键)颜色保持不变,因为它应该是黑色,因为它正在成为非关键字。为此,我在已接受答案的片段之后使用了以下代码。我希望它能帮助别人。谢谢!
@Override
public void afterTextChanged(Editable s) {
String string = s.toString();
String[] split = string.split("\s");
int startIndex = 0;
for(int i = 0 ; i < split.length ; i++){
String editable = split[i];
if(map.containsKey(editable)){
int index = string.indexOf(editable, startIndex);
int color = map.get(editable);
s.setSpan(new ForegroundColorSpan(color),
index,
index + editable.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
startIndex = index + editable.length();
}
if(!map.containsKey(editable)) {
int index = string.indexOf(editable, startIndex);
s.setSpan(new ForegroundColorSpan(Color.BLACK),
index,
index + editable.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
我在 EditText
中为高亮语法创建了简单的代码。
首先,我创建了一个 HashMap
来存储关键字和颜色。
Map<String,Integer> map = new HashMap<>();
map.put("public",Color.CYAN);
map.put("void", Color.BLUE);
map.put("String",Color.RED);
然后我为 EditText
添加了一个 TextWatcher
。
在 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);
}
}
}
如果我输入不同的词,例如 "public void String",此代码可以正常工作,但是当我输入时它不起作用 同样的词,"public public public"。它只为第一个单词设置颜色。
我怎样才能完成这项工作?谢谢。
由于每次for循环后查找索引的起始位置总是相同的,所以我添加了一个startIndex来记录变化的起始位置,这里是示例代码:
public void afterTextChanged(Editable editable) {
String string = editable.toString();
String[] split = string.split("\s");
int startIndex = 0;
for(int i = 0 ; i < split.length ; i++){
String s = split[i];
if(map.containsKey(s)){
int index = string.indexOf(s, startIndex);
int color = map.get(s);
editable.setSpan(new ForegroundColorSpan(color),
index,
index + s.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
startIndex = index + s.length();
}
}
}
使用string.indexOf(s)
将获得第一次出现。您可以使用正则表达式,而不是使用关键字映射并使用 indexOf
。我很快就写了这个作为例子:
下面示例 EditText 的屏幕截图:
示例:
final EditText editText = new EditText(this);
editText.addTextChangedListener(new TextWatcher() {
ColorScheme keywords = new ColorScheme(
Pattern.compile(
"\b(package|transient|strictfp|void|char|short|int|long|double|float|const|static|volatile|byte|boolean|class|interface|native|private|protected|public|final|abstract|synchronized|enum|instanceof|assert|if|else|switch|case|default|break|goto|return|for|while|do|continue|new|throw|throws|try|catch|finally|this|super|extends|implements|import|true|false|null)\b"),
Color.CYAN
);
ColorScheme numbers = new ColorScheme(
Pattern.compile("(\b(\d*[.]?\d+)\b)"),
Color.BLUE
);
final ColorScheme[] schemes = { keywords, numbers };
@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) {
removeSpans(s, ForegroundColorSpan.class);
for (ColorScheme scheme : schemes) {
for(Matcher m = scheme.pattern.matcher(s); m.find();) {
s.setSpan(new ForegroundColorSpan(scheme.color),
m.start(),
m.end(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
void removeSpans(Editable e, Class<? extends CharacterStyle> type) {
CharacterStyle[] spans = e.getSpans(0, e.length(), type);
for (CharacterStyle span : spans) {
e.removeSpan(span);
}
}
class ColorScheme {
final Pattern pattern;
final int color;
ColorScheme(Pattern pattern, int color) {
this.pattern = pattern;
this.color = color;
}
}
});
由于一些答案已经被接受,我想回答我遇到的一个问题,当时我按下退格键,单词从 "String" 变为 "Strin" 或 "Srn"(中间的退格键)颜色保持不变,因为它应该是黑色,因为它正在成为非关键字。为此,我在已接受答案的片段之后使用了以下代码。我希望它能帮助别人。谢谢!
@Override
public void afterTextChanged(Editable s) {
String string = s.toString();
String[] split = string.split("\s");
int startIndex = 0;
for(int i = 0 ; i < split.length ; i++){
String editable = split[i];
if(map.containsKey(editable)){
int index = string.indexOf(editable, startIndex);
int color = map.get(editable);
s.setSpan(new ForegroundColorSpan(color),
index,
index + editable.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
startIndex = index + editable.length();
}
if(!map.containsKey(editable)) {
int index = string.indexOf(editable, startIndex);
s.setSpan(new ForegroundColorSpan(Color.BLACK),
index,
index + editable.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}