如果我在Editable
上设置多个跨度,则使用最后一个ForegroundColorSpan
。在我看来,这是预期的行为。在Android 6.0+上,最新的设定范围不会优先。
下面是一个完整的工作示例,它突出显示EditText
中的数字和字符串:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the EditText view
EditText editText = new EditText(this);
editText.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
editText.setBackground(null);
editText.setGravity(Gravity.TOP);
// Patterns to find numbers and strings
final Pattern[] patterns = {
Pattern.compile("\\b(\\d*[.]?\\d+)\\b"), // numbers
Pattern.compile("\".*?\"|'.*?'"), // strings
};
// Colors for numbers and strings
final int[] colors = {
Color.RED,
Color.BLUE
};
// Add a TextWatcher to highlight numbers and strings
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 editable) {
// remove all spans before highlighting new text
ForegroundColorSpan[] spans = editable.getSpans(0, editable.length(), ForegroundColorSpan.class);
for (ForegroundColorSpan span : spans) {
editable.removeSpan(span);
}
// first, highlight numbers, next strings
for (int i = 0; i < patterns.length; i++) {
Pattern p = patterns[i];
Matcher m = p.matcher(editable);
while (m.find()) {
editable.setSpan(new ForegroundColorSpan(colors[i]), m.start(), m.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// print match
System.out.println(editable.subSequence(m.start(), m.end()));
}
}
// PROBLEM:
// On Android 6.0+ numbers are highlighted within the string.
// This is not expected behavior. It worked prior to Android 6.0
}
});
// set some text for testing purposes
editText.setText("foo \"bar\" baz \"quz 16\"");
setContentView(editText);
}
}
如果我启动此Activity
并输入文字
foo“bar”baz“qux 16”
我希望“bar”和“qux 16”都是蓝色的。但是,在Android 6.0及16
上为红色。
Android 5.1.1(预期行为)
Android 6.0.1
请注意第二个屏幕截图中如何突出显示16
。
为什么第一个颜色跨度会覆盖Android 6.0上的最后一个颜色跨度?如何解决此问题?
答案 0 :(得分:1)
如果在设置新ForegroundColorSpan
之前删除所有跨度,那么我会得到所需的行为。不幸的是,如果EditText
有大量文字,这还有很多工作要做。
我为修复做了什么:
@Override public void afterTextChanged(Editable editable) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// remove old spans before highlighting
// this does not work on Android 6.0+
ForegroundColorSpan[] spans = editable.getSpans(0, editable.length(), ForegroundColorSpan.class);
for (ForegroundColorSpan span : spans) {
editable.removeSpan(span);
}
}
for (int i = 0; i < patterns.length; i++) {
Pattern p = patterns[i];
Matcher m = p.matcher(editable);
while (m.find()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Remove any spans in the given range.
ForegroundColorSpan[] oldspans = editable.getSpans(m.start(), m.end(), ForegroundColorSpan.class);
for (ForegroundColorSpan span : oldspans) {
editable.removeSpan(span);
}
}
editable.setSpan(new ForegroundColorSpan(colors[i]), m.start(), m.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
我不确定Android 6.0+有什么变化,如果有人有任何见解,我们将不胜感激。