AndroidTextView的TextWatcher使用案例详解.docx
- 文档编号:6313922
- 上传时间:2023-05-09
- 格式:DOCX
- 页数:9
- 大小:56.18KB
AndroidTextView的TextWatcher使用案例详解.docx
《AndroidTextView的TextWatcher使用案例详解.docx》由会员分享,可在线阅读,更多相关《AndroidTextView的TextWatcher使用案例详解.docx(9页珍藏版)》请在冰点文库上搜索。
AndroidTextView的TextWatcher使用案例详解
TextWatcher一个文本变化监听接口,定义了三个接口,分别beforeTextChanged,onTextChanged,afterTextCahnged.TextWatcher通常与TextView结合使用,以便在文本变化的不同时机响应的处理。
TextWatcher中三个回调接口都使用了InputFilter过滤器过滤之后的文字字符作为新的字符对象。
使用方法
mTextView.aTextChangedListener(newTextWatcher(){
@Override
publicvoidbeforeTextChanged(CharSequences,intstart,intcount,intafter){
}
@Override
publicvoidonTextChanged(CharSequences,intstart,intbefore,intcount){
}
@Override
publicvoidafterTextChanged(Editables){//屏蔽回车中英文空格
}
});
们可以在beforeTextChanged,onTextChanged,afterTextChanged的回调方法中实现自己的逻辑,这三个参数代表了TextView文本发生变化的三个阶段。
beforeTextChanged(CharSequences,intstart,intcount,intafter)方法TextView在文本改变之前调用,并且传入四个参数。
CharSequences参数表示当前TextView内部的mText成员变量,实际上就当前显示的文本;intstart参数表示需要改变的文字区域的起,即选中的文本区域的起始;intcount参数表示需要改变的文字的字符数目,即选中的文本区域的字符的数目;intafter参数表示替换的文字的字符数目。
特别的,当TextView删除文本的时候,after的值为0,此时TextView使用用空字符串代替需要改变的文字区域来达到删除文字的目的。
图1.1描述了beforeTextChanged的四个参数的含义。
图1.1beforeTextChanged的四个参数实例
TextView的setText方法通过调用sendBeforeTextChanged方法通知所有注册的TextWatcher回调beforeTextChanged方法,此时传入的四个参数,s当前的本地变量mText的值,如果该值为null,即之前没有给TextView设置过需要显示的文本,那么s的值为"";start的值为0;count的值为当前mText的长度;after的值为需要显示的新文本的长度。
代码1.1TextView中setText方法调用sendBeforeTextChanged的源码。
代码1.1 TextView中setText方法调用sendBeforeTextChanged的源码
if(mText!
=null){
oldlen=mText.length();
sendBeforeTextChanged(mText,0,oldlen,text.length());
}else{
sendBeforeTextChanged("",0,0,text.length());
}
onTextChanged(CharSequences,intstart,intbefore,intcount)方法TextView在文本改变的时候调用,此时mText成员变量已经被为新的文本,并且传入四个参数。
CharSequences参数表示当前TextView内部的mText成员变量,此时的mText已经被过了,但此时mText所表示的文本还没有被显示到UI组件上;intstart参数表示改变的文字区域的起;intbefore参数表示改变的文字区域在改变前的旧的文本长度,即选中文字区域的文本长度;intafter参数表示改变的文字区域在后的新的文本长度。
特别的,当TextView文本的时候,before的值为0,此时相当于TextView将空的字符区域用新的文本代替。
afterTextChanged(Editables)方法TextView在调用完所有已注册的TextWatcher的onTextChanged方法之后回调的。
此时mText成员变量已经被为新的文本,并且传入s,该参数s实际上就mText。
通过该接口,咱们可以再次将要展示的文字。
图1.2描述了这三个方法在TextView文字变化时的调用流程。
图1.2 TextView文字变化时的调用流程
afterTextChanged的参数类型Editable,这一个可编辑的对象,该对像就Textview的内部变量mText,此时的mText·可编辑的,实际上一个SpannableStringBuilder对象。
代码1.1TextView的setText方法中text的转换逻辑。
从代码中可以看出,当type==BufferType.EDITABLE||getKeyListener()!
=null|| needEditableForNotification为true的时候,mEditableFactory会调用newEditable的方法创建一个可编辑的对象SpannableStringBuilder。
代码 1.1 TextView的setText方法中text的转换逻辑
booleanneedEditableForNotification=false;
if(mListeners!
=null&&mListeners.size()!
=0){
needEditableForNotification=true;
}
if(type==BufferType.EDITABLE||getKeyListener()!
=null||
needEditableForNotification){
createEditorIfNeeded();
Editablet=mEditableFactory.newEditable(text);
text=t;
setFilters(t,mFilters);
InputMethodManagerimm=InputMethodManager.peekInstance();
if(imm!
=null)imm.restartInput(this);
}elseif(type==BufferType.SPANNABLE||mMovement!
=null){
text=mSpannableFactory.newSpannable(text);
}elseif(!
(textinstanceofCharWrapper)){
text=TextUtils.stringOrSpannedString(text);
}
代码1.2mEditableFactory的newEditable方法,该方法一个工厂方法,创建一个SpannableStringBuilder对象。
代码 1.2 mEditableFactory的newEditable方法
publicEditablenewEditable(CharSequencesource){
returnnewSpannableStringBuilder(source);
}
SpannableStringBuilder实现了CharSequence,GetChars,Spannable,Editable,Appendable,GraphicsOperations的接口,内部的string可以变化的。
不过咱们afterTextChanged中的参数s的时候,需要注意循环调用的潜在风险,因为SpannableStringBuilder会在自己内部保存TextView的mChangeWatcher对象,代码1.3描述了设置过程。
如代码所示,text通过setSpan方法了mChangeWatcher对象,以监听整个text的变化,并且回调。
当text的内容发生变化的时候,会通过span机制调用mChangeWatcher中的相应方法。
代码1.3 TextView的setText方法给mTextmChangeWatcher的源码
Spannablesp=(Spannable)text;
//RemoveanyChangeWatchersthatmighthaveefromotherTextViews.
finalChangeWatcher[]watchers=sp.getSpans(0,sp.length(),ChangeWatcher.class);
finalintcount=watchers.length;
for(inti=0;i sp.removeSpan(watchers[i]); } if(mChangeWatcher==null)mChangeWatcher=newChangeWatcher(); sp.setSpan(mChangeWatcher,0,textLength,Spanned.SPAN_INCLUSIVE_INCLUSIVE| (CHANGE_WATCHER_PRIORITY< mChangeWatcher一个ChangeWatcher对象,ChangeWatcherTextView的内部类,实现了TextWatcher,SpanWatcher接口偶,代码1.4描述了ChangeWatcher实现的TextWatcher的三个回调接口。 这三个接口会分别调用TextView的相应的方法,通知所有注册的TextWatcher的调用相应的三个回调接口。 其中,TextView的handleTextChanged还会调用invalidate()和checkForResize()方法重绘UI界面. 代码1.4 ChangeWatcher实现的TextWatcher的三个回调接口 publicvoidbeforeTextChanged(CharSequencebuffer,intstart, intbefore,intafter){ ....... TextView.this.sendBeforeTextChanged(buffer,start,before,after); } publicvoidonTextChanged(CharSequencebuffer,intstart,intbefore,intafter){ ....... TextView.this.handleTextChanged(buffer,start,before,after); ...... } publicvoidafterTextChanged(Editablebuffer){ ...... TextView.this.sendAfterTextChanged(buffer); ...... } 通过SpannableStringBuilder,ChangeWatcher这两个类再加上span机制,android可以在文本改变的时候通知所有注册的TextWatcher方法调用相应的三个接口。 但这又会使咱们在TextWatcher的afterTextChanged中参数s的时候,再次调用TextWatcher的三个回调接口,这样如果afterTextChanged不能因为某些条件的判断,终止对s的,那么就会形成无限循环调用。 类似TextView的setText的方法也会在相应的时机通知所有注册的TextWatcher调用响应的三个接口,如果咱们在TextWatcher的三个接口中调用TextView的setText方法也会导致无限循环调用。 图1.3描述了无限调用的示例。 图1.3无限调用示例 但有时候们可能需要根据需求更改显示的文本,比如过滤不必要的字符,过滤非法的文字,必要的结束字符等。 这个时候们有时候会给TextView一个TextWatcher,然后在某个接口回调中根据传入的参数将要显示的文本,这可以满足咱们的需求,不过有可能会导致无限循环调用。 针对这个问题,咱们可以通过InputFilter来完成文本的目的。 InputFilter一个接口,内部定义了filter方法,这个方法的作用传入的字符串,如果返回值为null,那么保持原来的字符串。 代码1.5这个方法的定义。 代码1.5 InputFilter内部定义了filter接口 publicCharSequencefilter(CharSequencesource,intstart,intend, Spanneddest,intdstart,intdend); 如代码所示,filter方法需要传入六个参数,其中 source参数即将替换选中字符区域的字符串对象; start参数表示source的起始位置; end参数表示source的终止位置。 通过source,start,end这三个参数可以描述出替换选中字符区域的新的字符串。 dest表示选中文字区域的文本对象,TextView的setText方法调用filter方法时,传入的dest为 EMPTY_SPANNED,文字时,传入的 dest为TextView中保存的mText; dstart表示选中的文字区域的起始位置; dend表示选中的文字区域的终止位置。 该方法的返回值用来替换source作为新的替换文本。 图1.4有一个filter实例,描述了filter的六个参数的含义。 图1.4filter实例 InputFilter接口内部了两个子类,分别AllCaps和LengthFilter。 AllCaps将文本中的小写字符全部转为写字符的过滤器,通过该过滤器,TextView能将输入文本中的小写字符转为写字符,然后显示出来; LengthFilter删除掉超过长度maxLength的字符的过滤器。 在xml中配置了maxLength之后,TextView在创建实例的时候,会生成一个LengthFilter的过滤器,以便达到限定显示字符长度的功能。 咱们自己也可以定义满足咱们需求的inputfilter,以达到在TextWatcher接口回调之前过滤掉无用或者非法字符的功能,代码1.6一个InputFilter的实现子类,该类过滤掉无用的空白符。 代码1.6过滤掉无用空白符的过滤器 staticclassNoUsageCharInputFilterimplementsInputFilter{ @Override publicCharSequencefilter(CharSequencesource,intstart,intend,Spanneddest,intdstart,intdend){ returnsource==null? null: source.toString().replaceAll("\\s",""); } } 定义完InputFilter的实现子类之后,咱们就可以将实现了的过滤器到TextView的过滤器数组中,代码1.7一个过滤器的示例,如代码所示,通过source.setFilters(inputFilters)方法可以给TextView设置InputFilter数组,由于们的功能过滤器,因此需要将source原本的过滤器数组中的元素到新的过滤器数组中,否则source原本的过滤器数组会被覆盖掉,那样即使咱们在xml文件中配置了maxLength,source也不会使用LengthInputFilter来限定文本的长度。 代码1.7 过滤器的示例 publicstaticvoidaNoUsageCharInputFilter(TextViewsource){ if(source==null) return; InputFilter[]inputFilters=newInputFilter[source.getFilters()! =null? source.getFilters().length+1: 1]; inputFilters[0]=newNoUsageCharInputFilter(); if(source.getFilters()! =null){ for(inti=0;i inputFilters[i+1]=source.getFilters()[i]; } source.setFilters(inputFilters); } TexView在设置完过滤器数组之后,它的setText方法会在调用sendBeforeTextChanged之前先用过滤器数组中的过滤器传入的文本参数,setText方法调用过滤器的实现见代码1.8。 代码1.8 TexView中setText调用过滤器的实现代码 intn=mFilters.length; for(inti=0;i CharSequenceout=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监听TextView文本变化的三个时机,并在回调函数中相应的处理; 2.但在回调函数中处理的时候,需要注意不要调用该TextView的setText方法,否则会发生无限循环调用; 3.在TextWatcher的回调接口afterTextChanged方法中参数s的时候,也要注意在了s之后,会触发文本变化,导致TextView中所有注册的TextWatcher再次回调自己的的三个回调函数,此时需要预防无限循环调用的发生。 4.如果需要传入文本,那么可以实现InputFilter接口,然后给TextView符合需求的过滤器; 5.给TextView自定义的过滤器的时候,需要注意使用setFilter方法设置过滤器会覆盖掉TextView原本的过滤器,如果不想舍弃TextView原本的过滤器,那么需要将原本的过滤器到新的过滤器数组中。 6.TextView使用InputFilter过滤器数组的时候,从个过滤器到最后一个过滤器依次使用的,因此咱们给TextView设置过滤器数组的时候需要考虑过滤器的顺序。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AndroidTextView TextWatcher 使用 案例 详解