EditText是最常用的控件。很多情况下都要求只能输入特定的字符。比如只能输入整数,只能输入两位小数等。
为了满足EditText输入限制,大体上有两种方法:
- 给EditText加TextWatcher,监听用户输入,如果输入不合法,作相应处理。
- 使用InputFilter。
两种方法都能实现,但感觉第一种方式不太好复用。考虑使用InputFilter的实现。
InputFilters can be attached to Editables to constrain the changes that can be made to them.
(InputFilters可以限制可输入控件的输入)
EditText继承TextView,TextView中有个setFilters方法,这个方法就是设置InputFilters的。需要注意的是,这个方法最好只调用一次,多次调用,只有最后一次才会生效(即会覆盖之前的操作)。
在实际使用中,只要实现InputFilter类,满足各种各样的输入限制就行了。InputFilter只有一个filter方法要实现。该方法有五个参数:
- CharSequence source:刚输入的还没显示出来的字符
- int start与int end:应该是输入字符的位置,输入一个字符时分别是0和1,删除时都是0.
- Spanned dest:已经在EditText中显示出来的字符。
- int dstart, int dend:输入字符要插入和删除的位置。
实现了一个XEditText类,该类继承自AppCompatEditText,实现了多个InputFilter满足输入限制的功能。
import android.content.Context;
import android.support.v7.widget.AppCompatEditText;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.AttributeSet;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* Created by 林下de夕阳 on 2017/4/28.
* 具有输入限制的EditText
*/
public class XEditText extends AppCompatEditText {
// 保存设置的所有输入限制
private List inputFilters;
public XEditText(Context context) {
super(context);
init();
}
public XEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public XEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
inputFilters = new ArrayList<>();
}
/**
* 设置允许输入的最大字符数
*/
public void setMaxLengthFilter(int maxLength) {
inputFilters.add(new InputFilter.LengthFilter(maxLength));
setFilters(inputFilters.toArray(new InputFilter[inputFilters.size()]));
}
/**
* 设置可输入小数位
*/
public void setDecimalFilter(int num) {
inputFilters.add(new SignedDecimalFilter(0, num));
setFilters(inputFilters.toArray(new InputFilter[inputFilters.size()]));
}
/**
* 设置最大值
* @param maxmum 允许的最大值
* @param numOfDecimal 允许的小数位
*/
public void setMaxmumFilter(double maxmum, int numOfDecimal) {
inputFilters.add(new MaxmumFilter(0, maxmum, numOfDecimal));
setFilters(inputFilters.toArray(new InputFilter[inputFilters.size()]));
}
/**
* 设置只能输入整数
* @param min 输入整数的最小值
*/
public void setIntergerFilter(int min) {
inputFilters.add(new SignedIntegerFilter(min));
setFilters(inputFilters.toArray(new InputFilter[inputFilters.size()]));
}
/**
* 只能够输入手机号码
*/
public void setTelFilter() {
inputFilters.add(new TelephoneNumberInputFilter());
setFilters(inputFilters.toArray(new InputFilter[inputFilters.size()]));
}
/**
* 小数位数限制
*/
private static final class SignedDecimalFilter implements InputFilter {
private final Pattern pattern;
SignedDecimalFilter(int min, int numOfDecimals) {
pattern = Pattern.compile("^" + (min < 0 ? "-?" : "")
+ "[0-9]*\\.?[0-9]" + (numOfDecimals > 0 ? ("{0," + numOfDecimals + "}$") : "*"));
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source.equals(".")) {
if (dstart == 0 || !(dest.charAt(dstart - 1) >= '0' && dest.charAt(dstart - 1) <= '9') || dest.charAt(0) == '0') {
return "";
}
}
if (source.equals("0") && (dest.toString()).contains(".") && dstart == 0) { //防止在369.369的最前面输入0变成0369.369这种不合法的形式
return "";
}
StringBuilder builder = new StringBuilder(dest);
builder.delete(dstart, dend);
builder.insert(dstart, source);
if (!pattern.matcher(builder.toString()).matches()) {
return "";
}
return source;
}
}
/**
* 限制输入最大值
*/
private static final class MaxmumFilter implements InputFilter {
private final Pattern pattern;
private final double maxNum;
MaxmumFilter(int min, double maxNum, int numOfDecimals) {
pattern = Pattern.compile("^" + (min < 0 ? "-?" : "")
+ "[0-9]*\\.?[0-9]" + (numOfDecimals > 0 ? ("{0," + numOfDecimals + "}$") : "*"));
this.maxNum = maxNum;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source.equals(".")) {
if (dstart == 0 || !(dest.charAt(dstart - 1) >= '0' && dest.charAt(dstart - 1) <= '9') || dest.charAt(0) == '0') {
return "";
}
}
if (source.equals("0") && (dest.toString()).contains(".") && dstart == 0) {
return "";
}
StringBuilder builder = new StringBuilder(dest);
builder.delete(dstart, dend);
builder.insert(dstart, source);
if (!pattern.matcher(builder.toString()).matches()) {
return "";
}
if (!TextUtils.isEmpty(builder)) {
double num = Double.parseDouble(builder.toString());
if (num > maxNum) {
return "";
}
}
return source;
}
}
/**
* 限制整数
*/
private static final class SignedIntegerFilter implements InputFilter {
private final Pattern pattern;
SignedIntegerFilter(int min) {
pattern = Pattern.compile("^" + (min < 0 ? "-?" : "") + "[0-9]*$");
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
StringBuilder builder = new StringBuilder(dest);
builder.insert(dstart, source);
if (!pattern.matcher(builder.toString()).matches()) {
return "";
}
return source;
}
}
/**
* 限制电话号码
*/
private static class TelephoneNumberInputFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
StringBuilder builder = new StringBuilder(dest);
builder.insert(dstart, source);
int length = builder.length();
if (length == 1) {
if (builder.charAt(0) == '1') {
return source;
} else {
return "";
}
}
if (length > 0 && length <= 11) {
int suffixSize = length - 2;
Pattern pattern = Pattern.compile("^1[3-9]\\d{" + suffixSize + "}$");
if (pattern.matcher(builder.toString()).matches()) {
return source;
} else {
return "";
}
}
return "";
}
}
}