2017-07-16 5 views
0

注:このバグhereのreproを含むGitHubレポを作成しました。クローンを作成してアプリを自分自身で試してみて、バグを確認してください。関連コードはhereです:コメント部分にはコメントが残っていますが、コメントを外してコメントを残すと、そのバグが発生します。EditTextでカスタムEditableを使用すると、編集中にエラーが発生する


私は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など、SSBではなくreturn thisなど)をSSBに転送するだけです。今

私はEditTextを持っていると私は編集したとき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の基本となるテキストとしてColoredTextを設定してみてください。上の例では、最初の行の任意の部分をタップしてHello world!とし、ランダムな文字を入力し始めます。 2行目が影響を受け、何らかの形で(改行や矢印キーに触れていなくても)、カーソルは最終的に2行目に流出します。入力した文字の中には、カーソルが移動しても表示されないものがあります。

ここでsetEditableFactoryの部分をコメントアウトして、setText()の間にテキストがSSBにコピーされ、再度アプリケーションを実行すると、不具合がないことがわかります。

扱うときにそれも、あなたがそのままsetEditableFactory一部を残す場合は動作しますが、

明らかに
SpannableStringBuilder text = new SpannableStringBuilder("Hello world!\nHello world again!"); 

textの変数の初期化を置き換え、setText()は、それがどんなEditableを受け入れるだろうと言うが、それはうまく動作しません。 SSB以外のものでなぜこれが起こり、どのように修正できますか?ありがとう。

+0

私は、 'SpannableStringBuilder'のソースコードを掘り下げて、' Editable'などのインターフェースで定義された責任を果たすだけでなく、 'SpanWatcher.onSpanChanged()'を 'この '。'EditText'の実際の仕事場である' DynamicLayout'は、渡された参照のメンバー(実際の 'ColoredSpan'インスタンスです)と等しいかどうかをチェックすることによって' onSpanChanged() 'に応答します。明らかに彼らは異なっており、私はこれが問題であると思われます。 –

+0

実際には 'SpannableStringBuilder'は' Editable'だけではありません。カスタムの 'Editable'サブクラスが必要な場合は、' SpannableStringBuilder'が動作するかもしれません。しかし、私はこれらのことについてはあまりよく分からないので、コメントとして投稿します。 –

+0

@DurgadassS問題を掘り下げて解決策を提供してくれてありがとう。私はSSBを拡張しようとしましたが、今は完全に動作しています。あなたが回答を投稿すると、私はそれを喜んで受け入れるでしょう。 –

答えて

2

SpannableStringBuilderのソースコードを掘って、私はそれは、インタフェースEditableによって定義された責任を果たすなどもthisを渡すことでSpanWatcher.onSpanChanged()を呼び出すことにより、スパンの変更を報告するだけでなく考え出しました。 DynamicLayout(実際の作業馬EditText)は、そのメンバー(実際のColoredSpanインスタンス)との間で等しいかどうかを確認することによってonSpanChanged()に応答します。明らかに彼らは異なっており、私はこれが問題であると思われます。

実際にSpannableStringBuilderは、Editableではありません。カスタムが必要な場合EditableサブクラスSpannableStringBuilderが動作する可能性があります。

関連する問題