注意:我已经创建了一个包含此错误here的repro的GitHub存储库。随意克隆并自己尝试应用程序以查看错误。相关代码为here:评论部分保留在评论中,它可以正常工作,取消注释,您将体验到该错误。
我正在为Android构建源代码编辑器应用程序。我有一个自定义Editable
类型,其中包含SpannableStringBuilder
(此后将其称为 SSB )。这是它的代码:
package com.bluejay.myapplication;
import android.text.Editable;
import android.text.InputFilter;
import android.text.SpannableStringBuilder;
public class ColoredText implements Editable {
private final SpannableStringBuilder builder;
public ColoredText(String rawText) {
assert rawText != null;
this.builder = new SpannableStringBuilder(rawText);
}
@Override
public Editable replace(int st, int en, CharSequence source, int start, int end) {
this.builder.replace(st, en, source, start, end);
return this;
}
@Override
public Editable replace(int st, int en, CharSequence text) {
this.builder.replace(st, en, text);
return this;
}
@Override
public Editable insert(int where, CharSequence text, int start, int end) {
this.builder.insert(where, text, start, end);
return this;
}
@Override
public Editable insert(int where, CharSequence text) {
this.builder.insert(where, text);
return this;
}
@Override
public Editable delete(int st, int en) {
this.builder.delete(st, en);
return this;
}
@Override
public Editable append(CharSequence text) {
this.builder.append(text);
return this;
}
@Override
public Editable append(CharSequence text, int start, int end) {
this.builder.append(text, start, end);
return this;
}
@Override
public Editable append(char text) {
this.builder.append(text);
return this;
}
@Override
public void clear() {
this.builder.clear();
}
@Override
public void clearSpans() {
this.builder.clearSpans();
}
@Override
public void setFilters(InputFilter[] filters) {
this.builder.setFilters(filters);
}
@Override
public InputFilter[] getFilters() {
return this.builder.getFilters();
}
@Override
public void getChars(int start, int end, char[] dest, int destoff) {
this.builder.getChars(start, end, dest, destoff);
}
@Override
public void setSpan(Object what, int start, int end, int flags) {
this.builder.setSpan(what, start, end, flags);
}
@Override
public void removeSpan(Object what) {
this.builder.removeSpan(what);
}
@Override
public <T> T[] getSpans(int start, int end, Class<T> type) {
return this.builder.getSpans(start, end, type);
}
@Override
public int getSpanStart(Object tag) {
return this.builder.getSpanStart(tag);
}
@Override
public int getSpanEnd(Object tag) {
return this.builder.getSpanEnd(tag);
}
@Override
public int getSpanFlags(Object tag) {
return this.builder.getSpanFlags(tag);
}
@Override
public int nextSpanTransition(int start, int limit, Class type) {
return this.builder.nextSpanTransition(start, limit, type);
}
@Override
public int length() {
return this.builder.length();
}
@Override
public char charAt(int index) {
return this.builder.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return this.builder.subSequence(start, end);
}
}
如您所见,此类型是SSB的简单包装器。 new ColoredText(str)
从str
创建基础SSB及其所有方法调用(append
,delete
等除外return this
而不是EditText
SSB)简单地转发到SSB。
现在当我有ColoredText
时,我尝试将EditText
设置为EditText editText = (EditText) findViewById(R.id.editText);
// By default, setText() will attempt to copy the passed CharSequence into a new SSB.
// See https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/TextView.java#L4396
// and https://github.com/android/platform_frameworks_base/blob/master/core/java/android/text/Editable.java#L143
// I want to prevent this and have the ColoredText instead of an SSB be the EditText's
// underlying text, that is, I want the mText member to be of type ColoredText.
editText.setEditableFactory(new Editable.Factory() {
@Override
public Editable newEditable(CharSequence source) {
return (Editable) source; // source is ColoredText
}
});
ColoredText text = new ColoredText("Hello world!\nHello world again!");
editText.setText(text, TextView.BufferType.EDITABLE);
的基础文本,就像这样
EditText
Hello world!
在编辑时会表现得非常糟糕。在上面的示例中,使用setEditableFactory
点击第一行的任意位置,然后开始输入随机字符。第二行将受到影响,并且不知何故(即使您没有触摸换行符或箭头键),光标最终会溢出到第二行。即使光标移动,您输入的某些字符也可能无法显示。
现在,如果您注释掉setText()
部分,那么在setEditableFactory
期间将文本复制到SSB中,然后再次运行应用程序,您将看到没有任何故障。
如果您保持text
部分完好无损,但是将SpannableStringBuilder text = new SpannableStringBuilder("Hello world!\nHello world again!");
的变量初始化替换为
setText()
显然,尽管Editable
表示它会接受任何from selenium import webdriver
from selenium.webdriver.common.keys import Keys
kw = input("enter the keyword to search on google")
# creates firefox session
driver = webdriver.Firefox(executable_path=r'C:\Users\Web\Desktop\geckodriver-v0.18.0-win32\geckodriver.exe')
driver.implicitly_wait(30)
# navigate to google
driver.get("http://www.google.com")
#get the search textfield
search_field = driver.find_element_by_id("lst-ib")
search_field.clear()
#enter search kw and submit
search_field.send_keys(kw)
search_field.submit()
lists = driver.find_element_by_class_name("_Rm")
print ("Found " + str(len(lists)) + "searches:")
i=0
for listitem in lists:
print(listitem)
i=i+1
if(i>10):
break
driver.quit()
,但在处理SSB以外的任何内容时效果都不佳。为什么会发生这种情况,我该如何解决?感谢。
答案 0 :(得分:2)
通过挖掘SpannableStringBuilder
的源代码,我发现它不仅履行了接口Editable
等定义的职责,而且还通过调用SpanWatcher.onSpanChanged()
来报告跨度变化。通过this
。 DynamicLayout
(EditText
的真正主力)通过检查传入引用与其成员(这是我们实际的onSpanChanged()
实例)的相等性来响应ColoredSpan
。显然他们是不同的,我怀疑这是一个问题。
实际上SpannableStringBuilder
不只是Editable
,而是更多。如果您需要自定义Editable
子类SpannableStringBuilder
可能有效。