欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android TextView的TextWatcher使用案例詳解

 更新時間:2021年09月01日 09:24:46   作者:LuckySort  
這篇文章主要介紹了Android TextView的TextWatcher使用案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下

TextWatcher是一個文本變化監(jiān)聽接口,定義了三個接口,分別是beforeTextChanged,onTextChanged,afterTextCahnged. TextWatcher通常與TextView結(jié)合使用,以便在文本變化的不同時機(jī)做響應(yīng)的處理。TextWatcher中三個回調(diào)接口都是使用了InputFilter過濾器過濾之后的文字字符作為新的字符對象。

使用方法

mTextView.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 s) { //屏蔽回車 中英文空格

        }
});

我們可以在beforeTextChanged,onTextChanged,afterTextChanged的回調(diào)方法中實現(xiàn)自己的業(yè)務(wù)邏輯,這三個參數(shù)代表了TextView文本發(fā)生變化的三個階段。

beforeTextChanged(CharSequence s, int start, int count, int after)方法是TextView在文本改變之前調(diào)用,并且傳入四個參數(shù)。 CharSequence s參數(shù)表示當(dāng)前TextView內(nèi)部的mText成員變量,實際上就是當(dāng)前顯示的文本; int start參數(shù)表示需要改變的文字區(qū)域的起點,即選中的文本區(qū)域的起始點; int count參數(shù)表示需要改變的文字的字符數(shù)目,即選中的文本區(qū)域的字符的數(shù)目; int after參數(shù)表示替換的文字的字符數(shù)目。 特別的,當(dāng)TextView刪除文本的時候,after的值為0,此時TextView使用用空字符串代替需要改變的文字區(qū)域來達(dá)到刪除文字的目的。 圖1.1描述了beforeTextChanged的四個參數(shù)的含義。

圖1.1 beforeTextChanged的四個參數(shù)實例

TextView的setText方法通過調(diào)用sendBeforeTextChanged方法通知所有注冊的TextWatcher回調(diào)beforeTextChanged方法,此時傳入的四個參數(shù),s是當(dāng)前的本地變量mText的值,如果該值為null,即之前沒有給TextView設(shè)置過需要顯示的文本,那么s的值為"";start的值為0;count的值為當(dāng)前mText的長度;after的值為需要顯示的新文本的長度。代碼1.1是TextView中setText方法調(diào)用sendBeforeTextChanged的源碼。

代碼1.1 TextView中setText方法調(diào)用sendBeforeTextChanged的源碼

if ( mText !=  null) {
    oldlen =  mText.length() ;
    sendBeforeTextChanged( mText ,  0 , oldlen , text.length()) ;
}  else {
    sendBeforeTextChanged( "" ,  0 ,  0 , text.length()) ;
}

onTextChanged(CharSequence s, int start, int before, int count)方法是TextView在文本改變的時候調(diào)用,此時mText成員變量已經(jīng)被修改為新的文本,并且傳入四個參數(shù)。 CharSequence s參數(shù)表示當(dāng)前TextView內(nèi)部的mText成員變量,此時的mText已經(jīng)被修改過了,但此時mText所表示的文本還沒有被顯示到UI組件上; int start參數(shù)表示改變的文字區(qū)域的起點; int before參數(shù)表示改變的文字區(qū)域在改變前的舊的文本長度,即選中文字區(qū)域的文本長度; int after參數(shù)表示改變的文字區(qū)域在修改后的新的文本長度。 特別的,當(dāng)TextView添加文本的時候,before 的值為0,此時相當(dāng)于TextView將空的字符區(qū)域用新的文本代替。

afterTextChanged(Editable s)方法是TextView在調(diào)用完所有已注冊的TextWatcher的onTextChanged方法之后回調(diào)的。此時mText成員變量已經(jīng)被修改為新的文本,并且傳入s,該參數(shù)s實際上就是mText。通過該接口,咱們可以再次修改將要展示的文字。

圖1.2描述了這三個方法在TextView文字變化時的調(diào)用流程。

圖1.2  TextView文字變化時的調(diào)用流程

afterTextChanged的參數(shù)類型是Editable,這是一個可編輯的對象,該對像就Textview的內(nèi)部變量mText,此時的mText是·可編輯的,實際上是一個SpannableStringBuilder對象。代碼1.1是TextView的setText方法中text的轉(zhuǎn)換邏輯。從代碼中可以看出,當(dāng)type == BufferType.EDITABLE || getKeyListener() != null || needEditableForNotification為true的時候,mEditableFactory會調(diào)用newEditable的方法創(chuàng)建一個可編輯的對象SpannableStringBuilder。

代碼  1.1  TextView的setText方法中text的轉(zhuǎn)換邏輯

boolean needEditableForNotification =  false;

if ( mListeners !=  null &&  mListeners.size() !=  0) {
    needEditableForNotification =  true;
}

if (type == BufferType. EDITABLE || getKeyListener() !=  null ||
        needEditableForNotification) {
    createEditorIfNeeded() ;
    Editable t =  mEditableFactory.newEditable(text) ;
    text = t ;
    setFilters(t ,  mFilters) ;
    InputMethodManager imm = InputMethodManager.peekInstance() ;
    if (imm !=  null) imm.restartInput( this) ;
}  else if (type == BufferType. SPANNABLE ||  mMovement !=  null) {
    text =  mSpannableFactory.newSpannable(text) ;
}  else if (!(text  instanceof CharWrapper)) {
    text = TextUtils. stringOrSpannedString(text) ;
}

代碼1.2是mEditableFactory的newEditable方法,該方法是一個工廠方法,創(chuàng)建一個 SpannableStringBuilder對象。

代碼  1.2  mEditableFactory的newEditable方法

public Editable  newEditable(CharSequence source) {
    return new SpannableStringBuilder(source) ;
}

SpannableStringBuilder實現(xiàn)了CharSequence, GetChars, Spannable, Editable,Appendable, GraphicsOperations的接口,內(nèi)部的string是可以變化的。不過咱們修改afterTextChanged 中的參數(shù)s的時候, 需要注意循環(huán)調(diào)用的潛在風(fēng)險,因為SpannableStringBuilder會在自己內(nèi)部保存TextView的mChangeWatcher對象,代碼1.3描述了設(shè)置過程。如代碼所示,text通過setSpan方法添加了mChangeWatcher對象,以監(jiān)聽整個text的變化,并且做回調(diào)。當(dāng)text的內(nèi)容發(fā)生變化的時候,會通過span機(jī)制調(diào)用mChangeWatcher中的相應(yīng)方法。

代碼1.3 TextView的setText方法給mText添加mChangeWatcher的源碼

Spannable sp = (Spannable) text ;

// Remove any ChangeWatchers that might have come from other TextViews.
final ChangeWatcher[] watchers = sp.getSpans( 0 , sp.length() , ChangeWatcher. class) ;
final int count = watchers. length ;
for ( int i =  0 ; i < count ; i++) {
    sp.removeSpan(watchers[i]) ;
}

if ( mChangeWatcher ==  null)  mChangeWatcher =  new ChangeWatcher() ;

sp.setSpan( mChangeWatcher ,  0 , textLength , Spanned. SPAN_INCLUSIVE_INCLUSIVE |
        ( CHANGE_WATCHER_PRIORITY << Spanned. SPAN_PRIORITY_SHIFT)) ;

mChangeWatcher是一個ChangeWatcher對象,ChangeWatcher是TextView的內(nèi)部類,實現(xiàn)了TextWatcher, SpanWatcher接口偶,代碼1.4描述了ChangeWatcher實現(xiàn)的TextWatcher的三個回調(diào)接口。這三個接口會分別調(diào)用TextView的相應(yīng)的方法,通知所有注冊的TextWatcher的調(diào)用相應(yīng)的三個回調(diào)接口。其中,TextView的handleTextChanged還會調(diào)用invalidate()和checkForResize()方法重繪UI界面.

代碼1.4 ChangeWatcher實現(xiàn)的TextWatcher的三個回調(diào)接口

public void  beforeTextChanged(CharSequence buffer , int start ,
                              int before , int after) {
    .......

    TextView. this.sendBeforeTextChanged(buffer , start , before , after) ;
}

public void  onTextChanged(CharSequence buffer , int start , int before , int after) {
    .......
    TextView. this.handleTextChanged(buffer , start , before , after) ;
    ......
}

public void  afterTextChanged(Editable buffer) {
    ......
    TextView. this.sendAfterTextChanged(buffer) ;
    ......
}

通過SpannableStringBuilder,ChangeWatcher這兩個類再加上span機(jī)制,android可以在文本改變的時候通知所有注冊的TextWatcher方法調(diào)用相應(yīng)的三個接口。但是這又會使咱們在TextWatcher的afterTextChanged中修改參數(shù)s的時候,再次調(diào)用TextWatcher的三個回調(diào)接口,這樣如果afterTextChanged不能因為某些條件的判斷,終止對s的修改,那么就會形成無限循環(huán)調(diào)用。 類似TextView的setText的方法也會在相應(yīng)的時機(jī)通知所有注冊的TextWatcher調(diào)用響應(yīng)的三個接口,如果咱們在TextWatcher的三個接口中調(diào)用TextView的setText方法也會導(dǎo)致無限循環(huán)調(diào)用。圖1.3描述了無限調(diào)用的示例。

圖1.3 無限調(diào)用示例

但是有時候我們可能 需要根據(jù)業(yè)務(wù)需求更改顯示的文本,比如過濾不必要的字符,過濾非法的文字,添加必要的結(jié)束字符等。這個時候我們有時候會給TextView添加一個TextWatcher,然后在某個接口回調(diào)中根據(jù)傳入的參數(shù)修改將要顯示的文本,這可以滿足咱們的業(yè)務(wù)需求,不過有可能會導(dǎo)致無限循環(huán)調(diào)用。針對這個問題,咱們可以 通過InputFilter來完成修改文本的目的。 InputFilter是一個接口,內(nèi)部定義了filter方法,這個方法的作用是修改傳入的字符串,如果返回值為null,那么保持原來的字符串。代碼1.5是這個方法的定義。

代碼1.5 InputFilter內(nèi)部定義了filter接口

public CharSequence  filter(CharSequence source , int start , int end ,
                           Spanned dest , int dstart , int dend) ;

如代碼所示,filter方法需要傳入六個參數(shù),其中

source參數(shù)是即將替換選中字符區(qū)域的字符串對象;

start參數(shù)表示source的起始位置;

end參數(shù)表示source的終止位置。通過source,start,end這三個參數(shù)可以描述出替換選中字符區(qū)域的新的字符串。

dest表示選中文字區(qū)域的文本對象,TextView的setText方法調(diào)用filter方法時,傳入的dest為

EMPTY_SPANNED,修改文字時,傳入的

       dest為TextView中保存的mText;

dstart表示選中的文字區(qū)域的起始位置;

dend表示選中的文字區(qū)域的終止位置。

該方法的返回值是用來替換source作為新的替換文本。

圖1.4是有一個filter實例,描述了filter的六個參數(shù)的含義。

圖1.4 filter實例

InputFilter接口內(nèi)部提供了兩個子類,分別是AllCaps和LengthFilter。

AllCaps是將文本中的小寫字符全部轉(zhuǎn)為大寫字符的過濾器,通過該過濾器,TextView能將輸入文本中的小寫字符轉(zhuǎn)為大寫字符,然后顯示出來;

LengthFilter是刪除掉超過長度maxLength的字符的過濾器。在xml中配置了maxLength之后,TextView在創(chuàng)建實例的時候,會生成一個LengthFilter的過濾器,以便達(dá)到限定顯示字符長度的功能。

咱們自己也可以定義滿足咱們業(yè)務(wù)需求的inputfilter,以達(dá)到在TextWatcher接口回調(diào)之前過濾掉無用或者非法字符的功能,代碼1.6是一個InputFilter的實現(xiàn)子類,該類過濾掉無用的空白符。

代碼1.6 過濾掉無用空白符的過濾器

static class NoUsageCharInputFilter  implements InputFilter {
    @Override
    public CharSequence  filter(CharSequence source , int start , int end , Spanned dest , int dstart , int dend) {
        return source ==  null ?  null : source.toString().replaceAll( " \\ s" ,  "") ;
    }
}

定義完InputFilter的實現(xiàn)子類之后,咱們就可以將實現(xiàn)了的過濾器添加到TextView的過濾器數(shù)組中,代碼1.7是一個添加過濾器的示例,如代碼所示,通過source.setFilters(inputFilters)方法可以給TextView設(shè)置InputFilter數(shù)組,由于我們的功能是添加過濾器,因此 需要將source原本的過濾器數(shù)組中的元素添加到新的過濾器數(shù)組中,否則source原本的過濾器數(shù)組會被覆蓋掉,那樣即使咱們在xml文件中配置了maxLength,source也不會使用LengthInputFilter來限定文本的長度。

代碼1.7   添加過濾器的示例

public static void  addNoUsageCharInputFilter(TextView source) {
    if (source ==  null)
        return;

    InputFilter[] inputFilters =  new InputFilter[source.getFilters() !=  null ? source.getFilters(). length +  1:  1] ;
    inputFilters[ 0] =  new NoUsageCharInputFilter() ;
    if (source.getFilters() !=  null) {
        for ( int i =  0 ; i < source.getFilters(). length ; i++)
            inputFilters[i +  1] = source.getFilters()[i] ;
    }

    source.setFilters(inputFilters) ;
}

TexView在設(shè)置完過濾器數(shù)組之后,它的setText方法會在調(diào)用sendBeforeTextChanged之前先用過濾器數(shù)組中的過濾器修改傳入的文本參數(shù),setText方法調(diào)用過濾器的實現(xiàn)見代碼1.8。

代碼1.8 TexView中setText調(diào)用過濾器的實現(xiàn)代碼

int n = mFilters.length;
for (int i = 0; i < n; i++) {
    CharSequence out = mFilters[i].filter(text, 0, text.length(), EMPTY_SPANNED, 0, 0);
    if (out != null) {
        text = out;
    }
}

if (notifyBefore) {
    if (mText != null) {
        oldlen = mText.length();
        sendBeforeTextChanged(mText, 0, oldlen, text.length());
    } else {
        sendBeforeTextChanged("", 0, 0, text.length());
    }
}

通過以上的分析:

1.咱們可以使用TextWatcher監(jiān)聽TextView文本變化的三個時機(jī),并在回調(diào)函數(shù)中做相應(yīng)的處理;

2.但是在回調(diào)函數(shù)中處理業(yè)務(wù)的時候,需要注意不要調(diào)用該TextView的setText方法,否則會發(fā)生無限循環(huán)調(diào)用;

3.在TextWatcher 的回調(diào)接口afterTextChanged方法中修改參數(shù)s的時候,也要注意在修改了s之后,會觸發(fā)文本變化,導(dǎo)致TextView中所有注冊的TextWatcher再次回調(diào)自己的的三個回調(diào)函數(shù),此時需要預(yù)防無限循環(huán)調(diào)用的發(fā)生。

4.如果需要修改傳入文本,那么可以實現(xiàn)InputFilter接口,然后給TextView添加符合業(yè)務(wù)需求的過濾器;

5.給TextView添加自定義的過濾器的時候,需要注意使用setFilter方法設(shè)置過濾器會覆蓋掉TextView原本的過濾器,如果不想舍棄TextView原本的過濾器,那么需要將原本的過濾器添加到新的過濾器數(shù)組中。

6.TextView使用InputFilter過濾器數(shù)組的時候,是從第一個過濾器到最后一個過濾器依次使用的,因此咱們給TextView設(shè)置過濾器數(shù)組的時候需要考慮過濾器的順序。

到此這篇關(guān)于Android TextView的TextWatcher使用案例詳解的文章就介紹到這了,更多相關(guān)Android TextView的TextWatcher使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

  • Android 實現(xiàn)無網(wǎng)絡(luò)傳輸文件的示例代碼

    Android 實現(xiàn)無網(wǎng)絡(luò)傳輸文件的示例代碼

    本篇文章主要介紹了Android 實現(xiàn)無網(wǎng)絡(luò)傳輸文件的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Android自定義控件之圓形/圓角的實現(xiàn)代碼

    Android自定義控件之圓形/圓角的實現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件之圓形/圓角的實現(xiàn)代碼,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Android實現(xiàn)讀寫JSON數(shù)據(jù)的方法

    Android實現(xiàn)讀寫JSON數(shù)據(jù)的方法

    這篇文章主要介紹了Android實現(xiàn)讀寫JSON數(shù)據(jù)的方法,以完整實例形式分析了Android解析及生成json數(shù)據(jù)的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Android使用MediaPlayer和TextureView實現(xiàn)視頻無縫切換

    Android使用MediaPlayer和TextureView實現(xiàn)視頻無縫切換

    這篇文章主要為大家詳細(xì)介紹了Android使用MediaPlayer和TextureView實現(xiàn)視頻無縫切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • Android 開發(fā)使用Activity實現(xiàn)加載等待界面功能示例

    Android 開發(fā)使用Activity實現(xiàn)加載等待界面功能示例

    這篇文章主要介紹了Android 開發(fā)使用Activity實現(xiàn)加載等待界面功能,結(jié)合實例形式詳細(xì)分析了Android基于Activity實現(xiàn)加載等待界面布局與功能操作技巧,需要的朋友可以參考下
    2020-05-05
  • Android 10 適配攻略小結(jié)

    Android 10 適配攻略小結(jié)

    這篇文章主要介紹了Android 10 適配攻略小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Android實現(xiàn)自定義圓形進(jìn)度條

    Android實現(xiàn)自定義圓形進(jìn)度條

    這篇文章主要介紹了Android自定義圓形進(jìn)度條實現(xiàn)代碼,進(jìn)度條在Android中教程經(jīng)常使用到,本文向大家分享了Android實現(xiàn)自定義圓形進(jìn)度條的代碼,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Compose?的?Navigation組件使用示例詳解

    Compose?的?Navigation組件使用示例詳解

    這篇文章主要為大家介紹了Compose?的?Navigation組件使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • android scrollview 自動滾動到頂部或者底部的實例

    android scrollview 自動滾動到頂部或者底部的實例

    這篇文章主要介紹了android scrollview 自動滾動到頂部或者底部的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 最新評論