Java 将“自定义可编辑”与EditText一起使用会使其在编辑时出现问题
注意:我已经创建了一个GitHub repo,其中包含此bug的复制。请随意克隆并亲自试用该应用程序,以查看bug。相关的代码是:注释部分保留在注释中,工作正常,取消注释,您将体验到错误Java 将“自定义可编辑”与EditText一起使用会使其在编辑时出现问题,java,android,android-edittext,textview,spannablestring,Java,Android,Android Edittext,Textview,Spannablestring,注意:我已经创建了一个GitHub repo,其中包含此bug的复制。请随意克隆并亲自试用该应用程序,以查看bug。相关的代码是:注释部分保留在注释中,工作正常,取消注释,您将体验到错误 我正在为Android构建一个源代码编辑器应用程序。我有一个自定义的可编辑的类型,它包装了SpannableStringBuilder(以后称为SSB)。代码如下: package com.bluejay.myapplication; import android.text.Editable; import
我正在为Android构建一个源代码编辑器应用程序。我有一个自定义的
可编辑的
类型,它包装了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);
}
}
编辑文本时,EditText
的行为会非常容易出错。在上面的示例中,使用Hello world编码>并开始键入随机字符。第二行将受到影响,并且不知何故(即使您没有触摸换行符或箭头键),光标最终将溢出到第二行。即使光标移动,您键入的某些字符也可能无法显示
现在,如果您注释掉setEditableFactory
部分,那么文本将在setText()
期间复制到SSB中,并且再次运行该应用程序,您将看到没有任何故障
如果将setEditableFactory
部分保持不变,但将text
的变量初始化替换为
SpannableStringBuilder text = new SpannableStringBuilder("Hello world!\nHello world again!");
显然,尽管setText()
表示它将接受任何可编辑的
,但它在处理SSB以外的任何东西时都不起作用。为什么会发生这种情况?我如何修复它?谢谢。通过挖掘SpannableStringBuilder
的源代码,我发现它不仅履行了界面Editable
等定义的职责,而且还通过传递this
调用SpanWatcher.onSpanChanged()
来报告span更改DynamicLayout
(EditText
)的真正工作人员)通过检查传入引用与其成员(即实际的ColoredSpan
实例)的相等性来响应OnPanChanged()
。显然,他们是不同的,我怀疑这是一个问题
实际上,SpannableStringBuilder
不仅是可编辑的,而且还不止于此。如果您需要自定义可编辑的子类化SpannableStringBuilder
可能会起作用。通过挖掘SpannableStringBuilder
的源代码,我发现它不仅履行了接口可编辑的定义的职责,等等,但也可以通过调用SpanWatcher.onPanChanged()
来报告span更改,方法是传递this
DynamicLayout
(EditText
)的真正工作人员)通过检查传入引用与其成员(即实际的ColoredSpan
实例)的相等性来响应OnPanChanged()
。显然,他们是不同的,我怀疑这是一个问题
实际上,SpannableStringBuilder
不仅是可编辑的,而且还不止于此。如果您需要一个自定义的可编辑的子类化SpannableStringBuilder
可能会起作用。通过挖掘SpannableStringBuilder
的源代码,我发现它不仅履行了接口可编辑的定义的职责,等等,但也可以通过调用SpanWatcher.onPanChanged()
来报告span更改,方法是传递this
DynamicLayout
(EditText
)的真正工作人员)通过检查传入引用与其成员(即实际的ColoredSpan
实例)的相等性来响应OnPanChanged()
。显然,它们是不同的,我怀疑这是一个问题。实际上,SpannableStringBuilder
不仅仅是可编辑的,而且还不止于此。如果您需要自定义的可编辑的子类化SpannableStringBuilder
可以工作。然而,我对这些事情不是很确定,因此我将其作为评论发布。@Durgadass非常感谢您深入研究问题并提供解决方案。我试着扩展SSB,现在这个应用程序运行得很好。如果你发布一个答案,我很乐意接受。通过挖掘SpannableStringBuilder
的源代码,我发现它不仅履行了界面Editable
等定义的职责,而且还通过调用SpanWatcher.onSpanChanged()
传递this
来报告span更改DynamicLayout
(EditText
)的真正工作人员)通过检查传入引用与其成员(即实际的ColoredSpan
实例)的相等性来响应OnPanChanged()
。显然,它们是不同的,我怀疑这是一个问题。实际上,SpannableStringBuilder
不仅仅是可编辑的,而且还不止于此。如果您需要自定义的可编辑的子类化SpannableStringBuilder
可以工作。然而,我对这些事情不是很确定,因此我将其作为评论发布。@Durgadass非常感谢您深入研究问题并提供解决方案。我试着扩展SSB,现在这个应用程序运行得很好。如果你给我回信,我很乐意接受。
SpannableStringBuilder text = new SpannableStringBuilder("Hello world!\nHello world again!");