2017-07-16 36 views
0

說明:我創建了一個GitHub回購庫,其中包含此bug的代碼複製here。隨意克隆並自己嘗試應用程序以查看錯誤。相關的代碼是here:評論部分保留在評論中,它的工作正常,取消註釋,你會遇到錯誤。使用自定義Editing with EditText在編輯時會出現問題


我在爲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,並且其所有方法調用(除了appenddelete等等,其中return this代替SSB)簡單地轉發給SSB。

現在,當我有一個EditText,我嘗試設置ColoredTextEditText的基礎文本,像這樣

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()期間將文本複製到SSB中,然後再次運行該應用程序,您將看到沒有毛刺。

,如果你離開setEditableFactory部分完好,但

SpannableStringBuilder text = new SpannableStringBuilder("Hello world!\nHello world again!"); 

顯然取代text的變量初始化它甚至,雖然setText()說,它會接受任何Editable,它不能很好地工作打交道時除了SSB之外的其他任何東西。爲什麼會發生這種情況,我該如何解決?謝謝。

+0

通過挖掘'SpannableStringBuilder'的源代碼,我發現它不僅完成了Interfaces'Editable'等定義的職責,還通過調用'SpanWatcher.onSpanChanged()'來報告跨度變化, this'。'DynamicLayout'(EditText'的真正主力)通過檢查引用傳遞給它的成員(這是我們實際的'ColoredSpan'實例)的等式來響應'onSpanChanged()'。顯然他們是不同的,我懷疑這是一個問題。 –

+0

實際上'SpannableStringBuilder'不只是'可編輯的,但更多。如果你需要一個自定義的'Editable'子類,'SpannableStringBuilder'可以工作。不過,我對這些事情不是很確定,因此我把它作爲評論發佈。 –

+0

@DurgadassS非常感謝,無論是挖掘問題還是提供解決方案。我試圖擴展SSB,現在應用程序完美工作。如果您發佈答案,我會很樂意接受。 –

回答

2

挖的SpannableStringBuilder源代碼,我想通了,它不僅滿足了在接口Editable等定義的職責也由經過this調用SpanWatcher.onSpanChanged()報告的跨度變化。 DynamicLayoutEditText的真正主力)通過檢查與它的成員(這是我們的實際ColoredSpan實例)相關的參考傳遞的相等性來響應onSpanChanged()。顯然他們是不同的,我懷疑這是一個問題。其實SpannableStringBuilder不只是Editable,但更多。如果您需要定製Editable子類SpannableStringBuilder可能工作。

相關問題