前言:需求来了,产品小姐姐展现其高超技能的时候到了,接下来就是闪(粉)亮(墨)登场的时候了,a.登录账号只能输入数字;b.限制下位数;c.密码只输入数字字母和标点符号,总不能输入汉字吧;d.还有那个哪里哪里 你就输入汉字和字母就行了,哪有人的名字有数字啊?e.最重要的是不能输入表情符号等等。针对多才多艺的产品小姐姐,我一个彪形大汉(会写代码的文艺青年)肯定会怜香惜玉一一满足。针对这一有规律的需求,决定自定义View重写EditText来实现之。
项目背景
不想说
需求
- 限制输入表情符号
- 限制输入字数限制
- 英文、汉字、数字等可以多个并存限制字数和输入类型
实现思路
自定义View继承EditText,通过自定义属性来设置过滤器Filter控制输入类型和个数的限制。废话不多说直接上代码:
自定义属性如下:
<declare-styleable name="HandyEmojiEdittext">
<!-- 是否限制输入表情符号 默认限制 -->
<attr name="emojiFilterable" format="boolean|reference" />
<!-- 是否过滤空格 默认不过滤 -->
<attr name="filterSpace" format="boolean|reference" />
<!-- 输入长度 -->
<attr name="inputLength" format="integer|reference" />
<!-- 输入类型 -->
<attr name="inputTypeEnum">
<flag name="none" value="0x00" /><!--0000 0000-->
<flag name="en" value="0x01" /><!--0000 0001-->
<flag name="zh" value="0x02" /><!--0000 0010-->
<flag name="num" value="0x04" /><!--0000 0100-->
</attr>
<!-- 输入的最大整数 -->
<attr name="maxNum" format="integer|reference" />
</declare-styleable>
需要注意的是,inputTypeEnum 输入类型限制设置属性值的时候 跟TextView android:gravity="start|end" 使用规则一样,eg:app:inputTypeEnum="en|zh" 所以value只能是2^n
属性inputTypeEnum解释
算了~不解释了 ~
自己看~很简单的~
inputTypeEnum = typedArray.getInt(R.styleable.HandyEmojiEdittext_inputTypeEnum, 0);
switch (inputTypeEnum) {
case 0://none
inputTypeFilter = null;
break;
case 1://en
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[a-zA-Z]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 2://zh
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[\u4e00-\u9fa5]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 3://en & zh
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[a-zA-Z|\u4e00-\u9fa5]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 4://num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[0-9]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
if (maxNum != -1 && dest != null && !StringUtils.isEmpty(dest.toString().trim())) {
if (Integer.parseInt(dest.toString().trim() + source) <= maxNum) {
return source;
} else {
return "";
}
}
return source;
}
return "";
}
};
break;
case 5://en & num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[a-zA-Z|0-9]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 6://zh & num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[\u4e00-\u9fa5|0-9]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 7://en & zh & num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[0-9|a-zA-Z|\u4e00-\u9fa5]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
default:
inputTypeFilter = null;
break;
}
解释:en对应的value是1(0000 0001) zh对应的value是2(0000 0010), 则 en|zh=3(0000 0011)
过滤表情符号
敲黑板
if (emojiFilterable) {
emojiFilter = new InputFilter() {
Pattern emoji = Pattern.compile(
"[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher emojiMatcher = emoji.matcher(source);
if (emojiMatcher.find()) {
return "";
}
return source;
}
};
}
注意
由于是通过设置filter来实现输入限制的规则,那么就不能丢弃原有textview的filter,所以setFilters()方法追加filter来处理
InputFilter[] filters = new InputFilter[size + getFilters().length];
int i = 0;
for (InputFilter f : getFilters()) {
filters[i++] = f;
}
if (emojiFilter != null) {
filters[i++] = emojiFilter;
}
if (lengthFilter != null) {
filters[i++] = lengthFilter;
}
if (inputTypeFilter != null) {
filters[i++] = inputTypeFilter;
}
if (spaceFilter != null) {
filters[i] = spaceFilter;
}
setFilters(filters);
为了小伙伴的拿来主义,该自定义view的全部代码如下:
/**
* 描述:
* <p>
* 中英文
* [a-zA-Z|\u4e00-\u9fa5]
* 英文
* [a-zA-Z]
*
* @author coo_fee.
* @Time 2019/7/9.
*/
@SuppressLint("AppCompatCustomView")
public class HandyEmojiEdittext extends EditText {
/**
* 是否过滤表情
* true 默认过滤
*/
boolean emojiFilterable = true;
/**
* 是否过滤空格
* false 默认不过滤
*/
boolean mFilterSpace = false;
/**
* 输入长度限制
* <=0 表示没有限制
*/
int inputLength = 0;
/**
* 输入类型
* 0 none 没有限制
* 1 en 限制为英文
* 2 zh 限制为中文
* 3 en|zh 中文和英文
*/
int inputTypeEnum = 0;
/**
* 输入的最大整数
* -1 表示无限制
*/
int maxNum = -1;
public HandyEmojiEdittext(Context context) {
super(context);
init(context, null);
}
public HandyEmojiEdittext(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public HandyEmojiEdittext(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.HandyEmojiEdittext);
emojiFilterable = typedArray.getBoolean(R.styleable.HandyEmojiEdittext_emojiFilterable, true);
inputLength = typedArray.getInt(R.styleable.HandyEmojiEdittext_inputLength, 0);
inputTypeEnum = typedArray.getInt(R.styleable.HandyEmojiEdittext_inputTypeEnum, 0);
maxNum = typedArray.getInteger(R.styleable.HandyEmojiEdittext_maxNum, -1);
mFilterSpace = typedArray.getBoolean(R.styleable.HandyEmojiEdittext_filterSpace, false);
}
InputFilter emojiFilter = null;
InputFilter lengthFilter = null;
InputFilter inputTypeFilter = null;
InputFilter spaceFilter = null;
if (emojiFilterable) {
emojiFilter = new InputFilter() {
Pattern emoji = Pattern.compile(
"[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher emojiMatcher = emoji.matcher(source);
if (emojiMatcher.find()) {
return "";
}
return source;
}
};
}
if (mFilterSpace) {
spaceFilter = new InputFilter() {
Pattern space = Pattern.compile(
" ",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher spaceMatcher = space.matcher(source);
if (spaceMatcher.find()) {
return "";
}
return source;
}
};
}
if (inputLength > 0) {
lengthFilter = new InputFilter.LengthFilter(inputLength);
}
switch (inputTypeEnum) {
case 0://none
inputTypeFilter = null;
break;
case 1://en
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[a-zA-Z]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 2://zh
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[\u4e00-\u9fa5]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 3://en & zh
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[a-zA-Z|\u4e00-\u9fa5]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 4://num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[0-9]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
if (maxNum != -1 && dest != null && !StringUtils.isEmpty(dest.toString().trim())) {
if (Integer.parseInt(dest.toString().trim() + source) <= maxNum) {
return source;
} else {
return "";
}
}
return source;
}
return "";
}
};
break;
case 5://en & num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[a-zA-Z|0-9]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 6://zh & num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[\u4e00-\u9fa5|0-9]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
case 7://en & zh & num
inputTypeFilter = new InputFilter() {
Pattern inputTypePattern = Pattern.compile(
"[0-9|a-zA-Z|\u4e00-\u9fa5]",
Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
Matcher inputTypeMather = inputTypePattern.matcher(source);
if (inputTypeMather.find()) {
return source;
}
return "";
}
};
break;
default:
inputTypeFilter = null;
break;
}
int size = 0;
if (emojiFilter != null) {
++size;
}
if (lengthFilter != null) {
++size;
}
if (inputTypeFilter != null) {
++size;
}
if (spaceFilter != null) {
++size;
}
InputFilter[] filters = new InputFilter[size + getFilters().length];
int i = 0;
for (InputFilter f : getFilters()) {
filters[i++] = f;
}
if (emojiFilter != null) {
filters[i++] = emojiFilter;
}
if (lengthFilter != null) {
filters[i++] = lengthFilter;
}
if (inputTypeFilter != null) {
filters[i++] = inputTypeFilter;
}
if (spaceFilter != null) {
filters[i] = spaceFilter;
}
setFilters(filters);
}
}
StringUtils.isEmpty()如下:
public static boolean isEmpty(String str) {
return str == null || str.trim().length() == 0;
}
写在最后的话
无论多么帅气的代码,都抵挡不住测试兄弟们的骚操作,所以在他手贱复制过来粘贴的时候就不显灵了,欢迎小伙伴们留言、点赞、交流。
这篇博客介绍了如何在Android中自定义一个EditText,以过滤表情符号并限制输入字符的类型和数量。作者通过继承EditText并设置自定义属性来实现这一功能,详细讲解了实现思路、关键代码和注意事项。
455

被折叠的 条评论
为什么被折叠?



