本文主要介绍Android TextView的TextWatcher用例的详细说明。本文通过一个简单的案例来说明对这项技术的理解和使用。以下是详细内容。有需要的朋友可以参考一下。
TextWatcher是一个文本更改监控接口,定义了三个接口,分别是textchanged前、textchanged上、text cahanged后。Textwatcher通常与TextView结合使用,以响应不同时间的文本变化。TextWatcher中的三个回调接口都使用由InputFilter过滤器过滤的文本字符作为新的字符对象。
施用方式
mtextview . addtextchangedlistener(new text watcher(){
@覆盖
public void before text changed(char sequence s,int start,int count,int after) {
}
@覆盖
public void onTextChanged(char sequence s,int start,int before,int count) {
}
@覆盖
text changed(editable){//阻止回车中的中英文空格
}
});
我们可以在beforeTextChanged、onTextChanged和afterTextChanged的回调方法中实现自己的业务逻辑。这三个参数代表TextView文本更改的三个阶段。
beforeTextChanged(CharSequence s, int start, int count, int after)方法在文本更改之前由TextView调用,并传入四个参数。CharSequence s参数表示当前TextView内部的mText成员变量,实际上就是当前显示的文本;start参数表示要改变的文本区域的起点,即所选文本区域的起点;int参数表示要改变的文本中的字符数,即所选文本区域的字符数;int after参数指示被替换文本中的字符数。特别是,当TextView删除文本时,after的值为0。此时,TextView使用一个空字符串,而不是需要更改的文本区域来删除文本。图1.1描述了beforeTextChanged的四个参数的含义。
图TextChanged之前的四个参数示例
TextView的setText方法通过调用sendBeforeTextChanged方法通知所有注册的TextWatcher回调beforeTextChanged方法。此时,传入的四个参数s是当前局部变量mText的值。如果该值为null,即之前没有为TextView设置要显示的文本,则s的值为“”;start的值为0;count的值是当前多行文字的长度;after的值是要显示的新文本的长度。代码1.1是在TextView中调用sendBeforeTextChanged的设置文本方法的源代码。
1.1 textview中的setText方法调用sendBeforeTextChanged的源代码。
if(多行文字!=null) {
old len=mtext . length();
sendBeforeTextChanged( mText,0,oldlen,text . length());
}否则{
sendBeforeTextChanged(',0,0,text . length());
}
当文本改变时,TextView调用onTextChanged(CharSequence s, int start, int before, int count)方法。此时,多行文字成员变量已修改为新文字,并传入了四个参数。CharSequence的参数指示当前TextView中的mText成员变量。此时,多行文字已被修改,但多行文字所代表的文字尚未显示在UI组件上。start参数指示已更改文本区域的起点;Int before参数表示改变前已改变文本区域的旧文本长度,即所选文本区域的文本长度;Int after参数表示修改后已更改文本区域的新文本长度。特别是TextView添加文本时,before的值为0,相当于TextView用新的文本替换了空的字符区。
调用所有注册的TextWatcher的onTextChanged方法后,TextView将回调afterTextChanged(Editable s)方法。此时,mText成员变量已经被修改为新的文本,传入了s,这个参数s实际上就是mText。通过这个界面,我们可以修改要再次显示的文本。
图1.2描述了TextView文本改变时这三种方法的调用流程。
图1.2文本视图文本改变时的调用过程
更改后的文本的参数类型是可编辑,这是一个可编辑的对象,该对像就文本视图的内部变量多行文字,此时的多行文字是可编辑的,实际上是一个SpannableStringBuilder对象。代码1.1是文本视图的设置文本方法中文本的转换逻辑。从代码中可以看出,当type==BufferType .EDITABLE || getKeyListener()!=null | | needEditableForNotification为真实的的时候,医药工厂会调用新可编辑的方法创建一个可编辑的对象SpannableStringBuilder。
代码1.1文本视图的设置文本方法中文本的转换逻辑
boolean needEditableForNotification=false;
if ( mListeners!=null mListeners.size()!=0) {
needEditableForNotification=true;
}
if (type==BufferType .EDITABLE || getKeyListener()!=null ||
needEditableForNotification) {
createEditorIfNeeded();
可编辑t=可医疗工厂。新的可编辑(文本);
text=t;
setFilters(t,m过滤器);
输入方法经理IMM=输入方法经理。peek实例();
如果(imm!=null)IMM。重启输入(这个);
} else if (type==BufferType .SPANNABLE ||运动!=null) {
text=mspannablefactory。newspannable(文本);
} else if(!(包装材料的文本实例)){
text=TextUtils .stringOrSpannedString(文本);
}
代码1.2是医疗工厂的新可编辑方法,该方法是一个工厂方法,创建一个SpannableStringBuilder对象。
代码1.2医药工厂的新可编辑方法
公共可编辑newEditable(字符序列源){
返回新的SpannableStringBuilder(来源);
}
SpannableStringBuilder实现了CharSequence,GetChars,Spannable,可编辑,可追加,图形操作的接口,内部的线是可以变化的。不过咱们修改更改后的文本中的参数s的时候,需要注意循环调用的潜在风险,因为SpannableStringBuilder会在自己内部保存文本视图的mChangeWatcher对象,代码1.3描述了设置过程。如代码所示,文本通过设置跨度方法添加了mChangeWatcher对象,以监听整个文本的变化,并且做回调。当文本的内容发生变化的时候,会通过跨度机制调用mChangeWatcher中的相应方法。
代码1.3文本视图的设置文本方法给多行文字添加mChangeWatcher的源码
span able sp=(span able)text;
//移除可能来自其他文本视图的任何变革观察者.
最终更改观察器[]观察器=sp。get spans(0,sp.length(),更改观察器.类);
最终(同Internationalorganizations)国际组织计数=观察者。长度;
for(int I=0;我数;i ) {
物种删除span(watchers[I]);
}
if(mChangeWatcher==null)mChangeWatcher=new change watcher();
sp.setSpan( mChangeWatcher,0,textLength,Spanned .SPAN_INCLUSIVE_INCLUSIVE |
(更改_观察者_优先级跨越SPAN _ PRIORITY _ SHIFT));
mChangeWatcher是一个变革观察者对象,变更观察者是文本视图的内部类,实现了TextWatcher,SpanWatcher接口偶,代码1.4描述了变革观察者实现的文本观察者的三个回调接口。这三个接口会分别调用文本视图的相应的方法,通知所有注册的文本观察者的调用相应的三个回调接口。其中,文本视图的handleTextChanged还会调用无效()和checkForResize()方法重绘用户界面界面。
代码1.4变更观察者实现的文本观察者的三个回调接口
文本更改前的公共void(字符序列缓冲区,int start,
int before,int after) {
.
文本视图这个。sendbeforetextchanged(buffer,start,before,after);
}
public void onTextChanged(char sequence buffer,int start,int before,int after) {
.
文本视图this.handleTextChanged(buffer,start,before,after);
.
}
公共void afterTextChanged(可编辑缓冲区){
.
文本视图这个。sendfatetextchanged(缓冲区);
.
}
通过spannableStringBuilder和ChangeWatcher类以及Span机制,android可以在文本发生变化时通知所有注册的TextWatcher方法调用相应的三个接口。但这会导致我们在修改TextWatcher的afterTextChanged中的参数S时,再次调用TextWatcher的三个回调接口,这样如果因为某些条件,导致afterTextChanged无法终止对S的修改,就会形成一个无限循环调用。类似于TextView的setText方法也会通知所有注册的TextWatchers在相应的时间调用三个接口作为响应。如果我们在TextWatcher的三个接口中调用TextView的setText方法,也会导致无限循环调用。图1.3描述了一个无限调用的例子。
图1.3无限调用示例
但有时候我们可能是需要根据业务需求更改显示的文本,比如过滤不必要的字符,过滤非法文字,添加必要的结尾字符等。这时候我们有时会在TextView中添加一个TextWatcher,然后在一个接口回调中根据传入的参数修改要显示的文本。这可以满足我们的业务需求,但可能会导致无限循环调用。要解决这个问题,可以拨打通过InputFilter来完成修改文本的目的。Input是一个接口,filter方法是内部定义的。这个方法的功能是修改传入的字符串。如果返回值为null,将保留原始字符串。代码1.5是这种方法的定义。
代码1.5InputFilter在内部定义了过滤器接口。
公共CharSequence过滤器(CharSequence源,int开始,int结束,
Spanned dest,int dstart,int dend);
如代码所示,filter方法需要传入六个参数,其中
source参数是一个字符串对象,它将替换选定的字符区域;
start参数指示源的开始位置;
end参数指示源的结束位置。三个参数source、start和end可以描述替换所选字符区域的新字符串。
Dest代表选定文本区域中的文本对象。当TextView的setText方法调用filter方法时,传入的dest是
EMPTY _ SPANNED,修改文本时,传入的
Dest是保存在TextView中的多行文字;
Dstart表示所选文本区域的起始位置;
Den表示选定文本区域的结束位置。
此方法的返回值用于替换source作为新的替换文本。
图1.4显示了一个过滤器的例子,它描述了过滤器的六个参数的含义。
图1.4过滤器示例
InputFilter接口中提供了两个子类AllCaps和LengthFilter。
AllCaps是一个将文本中所有小写字符转换为大写字符的过滤器。通过这个过滤器,TextView可以将输入文本中的小写字符转换成大写字符,然后显示出来;
LengthFilter是一个删除超过长度maxLength的字符的过滤器。在xml中配置maxLength后,TextView在创建实例时会生成一个LengthFilter的过滤器,从而实现限制显示字符长度的功能。
咱们自己也可以定义满足咱们业务需求的inputfilter,以达到在TextWatcher接口回调之前过滤掉无用或者非法字符的功能,Code 1.6是InputFilter的实现子类,过滤掉无用的空格。
代码1.6过滤掉无用的空白
静态类NoUsageCharInputFilter实现InputFilter {
@覆盖
public char sequence filter(char sequence source,int start,int end,Spanned dest,int dstart,int dend) {
返回source==null?null : source.toString()。replaceAll( ' \\ s ',' ');
}
}
在定义了InputFilter的实现子类后,我们可以将实现的过滤器添加到TextView的过滤器数组中。代码1.7是添加过滤器的一个例子。如代码所示,可以通过source.setFilters(inputFilters)方法为TextView设置InputFilter数组。因为我们的功能是添加过滤器,所以需要将source原本的过滤器数组中的元素添加到新的过滤器数组中,否则source原本的过滤器数组会被覆盖掉,即使我们在xml文件中配置maxLength,source也不会使用LengthInputFilter来限制文本的长度。
1.7添加过滤器的示例
公共静态void addNoUsageCharInputFilter(TextView源){
if (source==null)
返回;
input filter[]input filters=new input filter[source . get filters()!=null?source.getFilters()。长度1:1];
input filters[0]=new NoUsageCharInputFilter();
if (source.getFilters()!=null) {
for(int I=0;i source.getFilters()。长度;我)
input filters[I 1]=source . get filters()[I];
}
source.setFilters(输入过滤器);
}
在TEX设置过滤器数组之后,它的setText方法将在调用sendBeforeTextChanged之前用过滤器数组中的过滤器修改传入的文本参数。setText方法调用过滤器的实现见代码1.8。
代码1.8 texview中setText调用过滤器的实现代码
int n=mFilters.length
for(int I=0;I n;i ) {
CharSequence out=mFilters[i]。filter(text,0,text.length(),EMPTY _ SPANNED,0,0);
如果(出!=null) {
text=out
}
}
if (notifyBefore) {
if(多行文字!=null) {
old len=mtext . length();
sendBeforeTextChanged(mText,0,oldlen,text . length());
}否则{
sendBeforeTextChanged(',0,0,text . length());
}
}
通过以上分析:
1.我们可以使用TextWatcher来监控TextView文本变化的三个机会,并在回调函数中做相应的处理;
2.但是在回调函数中处理业务时,需要注意不要调用TextView的setText方法,否则会出现无限循环调用;
3.在修改TextWatcher的回调接口afterTextChanged方法中的参数S时,还需要注意的是,修改S后会触发文本的改变,导致TextView中所有注册的text watcher再次回调它们的三个回调函数。这时候就要防止无限循环调用的发生。
4.如果需要修改传入文本,可以实现InputFilter接口,然后在TextView中添加符合业务需求的过滤器;
5.向TextView添加自定义滤镜时,需要注意的是,使用setFilter方法设置滤镜将会覆盖TextView的原始滤镜。如果不想丢弃TextView原来的滤镜,需要将原来的滤镜添加到新的滤镜数组中。
6.当TextView使用InputFilter数组时,从第一个滤镜到最后一个滤镜依次使用,所以我们在为TextView设置滤镜数组时需要考虑滤镜的顺序。
关于Android TextView的TextWatcher的用例的详细说明,本文到此为止。关于Android TextView使用TextWatcher的更多信息,请搜索我们之前的文章或继续浏览下面的相关文章。希望你以后能支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。