android 只能输入汉字,Android限制EditText只能输入中文或者指定内容的实现

最近项目中要限制EditText中只能输入中文,之前写过1个限制EditText只能输入中文的实现,不过存在1些问题,而且扩大性不是很好,所以换了1种方法来实现.

先看1下效果图:

f094f3c9033989358e87ed24270d29a2.gif

具体实现

1般对EditText的操作及处理都是用addTextChangedListener方法来对EditText进行监听,以后在监听方法中去做处理.这里也打算用这个种方法来做,大体的思路是监听EditText中输入的内容,然后将不是中文的部份清除掉,也就是置为空.所以大概应当这样写

mLimitEt.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) {

// 1.处理输入的内容s:清除其中不是中文的部份

...

// 2.设置处理完的s

mLimitEt.setText("处理以后的s");

}

@Override

public void afterTextChanged(Editable s) {

}

});

处理的方法这里先不写,先来看1下这样写会出现的1个问题,运行1下,输入1些内容会发现程序崩溃了,查看崩溃信息,会发现出现了StackOverflowError异常,这是甚么缘由呢?带着疑问去扒了1下源码(看源码时遇到1个问题,升级完Studio以后,发现没法查看源码了,查了1些资料解决了,也有相同问题的童鞋可以参考下我写的 Mac版Android Studio查看不到源码的解决方法,windows版解决方法也类似)出现异常的位置在 mLimitEt.setText()这句代码上,所以先看1下setText()方法.setText方法在TextView中,看1下实现(这里只关心引发异常的部份,其他部份的内容不讨论)

private void setText(CharSequence text, BufferType type,

boolean notifyBefore, int oldlen) {

...

// Text改变前的回调解理

sendBeforeTextChanged(mText, 0, oldlen, text.length());

...

// Text改变中的回调解理

sendOnTextChanged(text, 0, oldlen, textLength);

...

// Text改变后的回调解理

sendAfterTextChanged((Editable) text);

}

在setText方法中可以看到这几个方法,然后看1下这些方法做的处理是甚么

/**

* Not private so it can be called from an inner class without going

* through a thunk.

*/

void sendOnTextChanged(CharSequence text, int start, int before, int after) {

if (mListeners != null) {

final ArrayList list = mListeners;

final int count = list.size();

for (int i = 0; i < count; i++) {

list.get(i).onTextChanged(text, start, before, after);

}

}

if (mEditor != null) mEditor.sendOnTextChanged(start, after);

}

/**

* Not private so it can be called from an inner class without going

* through a thunk.

*/

void sendAfterTextChanged(Editable text) {

if (mListeners != null) {

final ArrayList list = mListeners;

final int count = list.size();

for (int i = 0; i < count; i++) {

list.get(i).afterTextChanged(text);

}

}

hideErrorIfUnchanged();

}

看1下这些方法,能不能发现点甚么,可以看到有1个ArrayList< TextWatcher >对象,先进行判空处理,如果这个对象中存在TextWatcher监听,则逐条进行回调操作.再回头看1下之前写的EditText中回调方法的实现,在回调中,对这个EditText进行了setText操作,由于EditText实现了TextWatcher的回调接口,这样就致使了无穷循环 setText->onTextChanged->setText…… 终究致使程序崩溃.那该如何解决这个问题呢.其实很简单,看1下代码

mLimitEt.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) {

// 1.处理输入的内容s:清除其中不是中文的部份

...

// 2.删除监听

mLimitEt.removeTextChangedListener(this);

// 3.设置处理完的s

mLimitEt.setText("处理以后的s");

// 4.重新添加监听

mLimitEt.addTextChangedListener(this);

}

@Override

public void afterTextChanged(Editable s) {

}

});

在setText之前先删除之前的回调监听,setText时由于没有TextWatcher的监听方法,所以不会出现无穷循环的情况,当setText以后再重新添加回调监听,这样就避免了崩溃的产生.以后看1下清除非中文部份的实现,直接看代码

/**

* 清除不是中文的内容

*

*@param regex

*@return

*/

private String clearLimitStr(String regex, String str) {

return str.replaceAll("[^\u4E00-\u9FA5]", "");

}

用了String的replaceAll方法来处理输入的内容(用了正则表达式,使用起来很简单).在onTextChanged和afterTextChanged方法中,得到的输入内容实际上是整体的输入内容,所以用replaceAll方法,可以去打印1下这几个方法中的参数,这里就不做了.看1下整体代码

LimitInputTextWatcher:

package com.example.junweiliu.limitinputdemo;

import android.text.Editable;

import android.text.TextWatcher;

import android.widget.EditText;

/**

* Created by junweiliu on 17/1/6.

*/

public class LimitInputTextWatcher implements TextWatcher {

/**

* et

*/

private EditText et = null;

/**

* 挑选条件

*/

private String regex;

/**

* 默许的挑选条件(正则:只能输入中文)

*/

private String DEFAULT_REGEX = "[^\u4E00-\u9FA5]";

/**

* 构造方法

*

*@param et

*/

public LimitInputTextWatcher(EditText et) {

this.et = et;

this.regex = DEFAULT_REGEX;

}

/**

* 构造方法

*

*@param et et

*@param regex 挑选条件

*/

public LimitInputTextWatcher(EditText et, String regex) {

this.et = et;

this.regex = regex;

}

@Override

public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

@Override

public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

@Override

public void afterTextChanged(Editable editable) {

String str = editable.toString();

String inputStr = clearLimitStr(regex, str);

et.removeTextChangedListener(this);

// et.setText方法可能会引发键盘变化,所以用editable.replace来显示内容

editable.replace(0, editable.length(), inputStr.trim());

et.addTextChangedListener(this);

}

/**

* 清除不符合条件的内容

*

*@param regex

*@return

*/

private String clearLimitStr(String regex, String str) {

return str.replaceAll(regex, "");

}

}

为了扩大性,提出来了1个类,提供了两个构造方法,如果需要限制其他的特殊内容,可以设置正则的规则.固然如果很简单的话,用EidtText自带的digits属性就能够了.还有1个问题,需要注意,代码中没有用et.setText方法,是由于setText方法可能引发键盘变化异常,所以这里用 editable.replace(0, editable.length(), inputStr.trim());这个方法和setText方法的实现效果是1样的.不过也需要对监听进行处理,缘由也是由于会引发无穷循环,感兴趣的童鞋可以去看1下.

完全代码

MainActivity:

package com.example.junweiliu.limitinputdemo;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

/**

* et

*/

private EditText mLimitEt;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mLimitEt = (EditText) findViewById(R.id.et_limit);

mLimitEt.addTextChangedListener(new LimitInputTextWatcher(mLimitEt));

// 去除除a-z A-Z与0⑼和中文的其他符号

// mLimitEt.addTextChangedListener(new LimitInputTextWatcher(mLimitEt, "[^a-zA-Z0⑼\u4E00-\u9FA5]"));

}

}

activity_main:

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.example.junweiliu.limitinputdemo.MainActivity">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerHorizontal="true"

android:hint="我是1个受限制的输入框"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerHorizontal="true"

android:text="复制我fuzhiwo845"

android:hint=""/>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值