【发布时间】:2011-03-21 22:02:05
【问题描述】:
我只想将字符限制为 0-9、a-z、A-Z 和空格键。设置 inputtype 我可以限制为数字,但我无法弄清楚 Inputfilter 浏览文档的方式。
【问题讨论】:
我只想将字符限制为 0-9、a-z、A-Z 和空格键。设置 inputtype 我可以限制为数字,但我无法弄清楚 Inputfilter 浏览文档的方式。
【问题讨论】:
我在另一个论坛上找到了这个。像冠军一样工作。
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!Character.isLetterOrDigit(source.charAt(i))) {
return "";
}
}
return null;
}
};
edit.setFilters(new InputFilter[] { filter });
【讨论】:
InputFilters 在显示字典建议的 Android 版本中有点复杂。您有时会在 source 参数中得到一个 SpannableStringBuilder,有时是一个普通的 String。
以下InputFilter 应该可以工作。随时改进此代码!
new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if (source instanceof SpannableStringBuilder) {
SpannableStringBuilder sourceAsSpannableBuilder = (SpannableStringBuilder)source;
for (int i = end - 1; i >= start; i--) {
char currentChar = source.charAt(i);
if (!Character.isLetterOrDigit(currentChar) && !Character.isSpaceChar(currentChar)) {
sourceAsSpannableBuilder.delete(i, i+1);
}
}
return source;
} else {
StringBuilder filteredStringBuilder = new StringBuilder();
for (int i = start; i < end; i++) {
char currentChar = source.charAt(i);
if (Character.isLetterOrDigit(currentChar) || Character.isSpaceChar(currentChar)) {
filteredStringBuilder.append(currentChar);
}
}
return filteredStringBuilder.toString();
}
}
}
【讨论】:
String replacement = source.subSequence(start, end).toString(); return replacement.replaceAll("[^A-Za-z0-9_\\-@]", "");
source instanceof SpannableStringBuilder 时,输入 AB 给了我 AAB 就像尝试上一个答案时一样。幸运的是,我能够通过使用下面的@florian 解决方案来解决它。
容易多了:
<EditText
android:inputType="text"
android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />
【讨论】:
","。你可以使用类似"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
imeOptions="actionNext"等。
所有发布的答案都不适合我。我有自己的解决方案:
InputFilter filter = new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
boolean keepOriginal = true;
StringBuilder sb = new StringBuilder(end - start);
for (int i = start; i < end; i++) {
char c = source.charAt(i);
if (isCharAllowed(c)) // put your condition here
sb.append(c);
else
keepOriginal = false;
}
if (keepOriginal)
return null;
else {
if (source instanceof Spanned) {
SpannableString sp = new SpannableString(sb);
TextUtils.copySpansFrom((Spanned) source, start, sb.length(), null, sp, 0);
return sp;
} else {
return sb;
}
}
}
private boolean isCharAllowed(char c) {
return Character.isLetterOrDigit(c) || Character.isSpaceChar(c);
}
}
editText.setFilters(new InputFilter[] { filter });
【讨论】:
EditText 已经可以拥有自己的过滤器,例如长度过滤器。因此,您很可能希望将您的过滤器添加到现有的过滤器中,而不是仅仅覆盖过滤器。
100% 满足您的需要,而且非常简单。
<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />
在strings.xml中
<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>
【讨论】:
避免输入类型中的特殊字符
public static InputFilter filter = new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String blockCharacterSet = "~#^|$%*!@/()-'\":;,?{}=!$^';,?×÷<>{}€£¥₩%~`¤♡♥_|《》¡¿°•○●□■◇◆♧♣▲▼▶◀↑↓←→☆★▪:-);-):-D:-(:'(:O 1234567890";
if (source != null && blockCharacterSet.contains(("" + source))) {
return "";
}
return null;
}
};
您可以将过滤器设置为您的编辑文本,如下所示
edtText.setFilters(new InputFilter[] { filter });
【讨论】:
为了简单起见,我做了这样的事情:
edit_text.filters = arrayOf(object : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
return source?.subSequence(start, end)
?.replace(Regex("[^A-Za-z0-9 ]"), "")
}
})
这样,我们将源字符串新部分中所有不需要的字符替换为空字符串。
edit_text 变量就是我们所指的EditText 对象。
代码写在kotlin。
【讨论】:
TextWatcher 将发生StackOverFlowError,除非执行以下检查,如下所示:link.medium.com/YfjQwprHUhb
除了接受的答案之外,还可以使用例如:android:inputType="textCapCharacters" 作为<EditText> 的属性,以便只接受大写字符(和数字)。
【讨论】:
没错,在 XML 布局本身中修复它的最佳方法是:
<EditText
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
正如 Florian Fröhlich 正确指出的那样,它甚至适用于文本视图。
<TextView
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
请注意,android:digits 中提到的字符只会显示,所以请注意不要错过任何一组字符:)
【讨论】:
inputType 不会影响过滤。
先加入strings.xml:
<string name="vin_code_mask">0123456789abcdefghjklmnprstuvwxyz</string>
XML:
android:digits="@string/vin_code_mask"
Code 在 Kotlin 中:
edit_text.filters += InputFilter { source, start, end, _, _, _ ->
val mask = getString(R.string.vin_code_mask)
for (i in start until end) {
if (!mask.contains(source[i])) {
return@InputFilter ""
}
}
null
}
奇怪,但它在模拟器的软键盘上运行很奇怪。
警告!以下代码将过滤除软件键盘的数字之外的所有字母和其他符号。智能手机上只会出现数字键盘。
edit_text.keyListener = DigitsKeyListener.getInstance(context.getString(R.string.vin_code_mask))
我也经常设置maxLength、filters、inputType。
【讨论】:
由于某种原因,android.text.LoginFilter 类的构造函数是包范围的,因此您不能直接扩展它(即使它与此代码相同)。但是您可以扩展 LoginFilter.UsernameFilterGeneric!然后你就有了这个:
class ABCFilter extends LoginFilter.UsernameFilterGeneric {
public UsernameFilter() {
super(false); // false prevents not-allowed characters from being appended
}
@Override
public boolean isAllowed(char c) {
if ('A' <= c && c <= 'C')
return true;
if ('a' <= c && c <= 'c')
return true;
return false;
}
}
这并没有真正记录,但它是核心库和source is straightforward 的一部分。我已经使用它一段时间了,到目前为止没有任何问题,尽管我承认我没有尝试过任何涉及跨度的复杂操作。
【讨论】:
当我需要防止用户在 EditText 中输入空字符串时,这个简单的解决方案对我有用。您当然可以添加更多字符:
InputFilter textFilter = new InputFilter() {
@Override
public CharSequence filter(CharSequence c, int arg1, int arg2,
Spanned arg3, int arg4, int arg5) {
StringBuilder sbText = new StringBuilder(c);
String text = sbText.toString();
if (text.contains(" ")) {
return "";
}
return c;
}
};
private void setTextFilter(EditText editText) {
editText.setFilters(new InputFilter[]{textFilter});
}
【讨论】:
您可以在正则表达式中指定想要的字符并在 InputFilter 中使用它:
val regex = Regex("[a-zA-Z\\d ]")
editText.filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
source.filter { regex.matches(it.toString()) }
})
注意,我没有使用\w 字符类,因为它包含下划线_
【讨论】:
如果您将 InputFilter 子类化,您可以创建自己的 InputFilter 来过滤掉任何非字母数字字符。
InputFilter 接口有一个方法,filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend),它为您提供了所有您需要知道的关于哪些字符被输入到分配给它的 EditText 的信息。
创建自己的 InputFilter 后,您可以通过调用 setFilters(...) 将其分配给 EditText。
http://developer.android.com/reference/android/text/InputFilter.html#filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int)
【讨论】:
忽略其他人处理过的跨度内容,为了正确处理字典建议,我发现以下代码有效。
来源随着建议的增加而增加,因此我们必须先查看它实际上希望我们替换多少个字符,然后再返回任何内容。
如果我们没有任何无效字符,则返回 null 以便进行默认替换。
否则,我们需要从子字符串中提取有效字符,这些字符实际上将被放入 EditText。
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
boolean includesInvalidCharacter = false;
StringBuilder stringBuilder = new StringBuilder();
int destLength = dend - dstart + 1;
int adjustStart = source.length() - destLength;
for(int i=start ; i<end ; i++) {
char sourceChar = source.charAt(i);
if(Character.isLetterOrDigit(sourceChar)) {
if(i >= adjustStart)
stringBuilder.append(sourceChar);
} else
includesInvalidCharacter = true;
}
return includesInvalidCharacter ? stringBuilder : null;
}
};
【讨论】:
防止在edittext中出现单词。 创建一个你可以随时使用的类。
public class Wordfilter implements InputFilter
{
@Override
public CharSequence filter(CharSequence source, int start, int end,Spanned dest, int dstart, int dend) {
// TODO Auto-generated method stub
boolean append = false;
String text = source.toString().substring(start, end);
StringBuilder str = new StringBuilder(dest.toString());
if(dstart == str.length())
{
append = true;
str.append(text);
}
else
str.replace(dstart, dend, text);
if(str.toString().contains("aaaaaaaaaaaa/*the word here*/aaaaaaaa"))
{
if(append==true)
return "";
else
return dest.subSequence(dstart, dend);
}
return null;
}
}
【讨论】:
这是一个旧线程,但有目的的解决方案都有问题(取决于设备/Android 版本/键盘)。
不同的方法
所以最终我采用了不同的方法,而不是使用有问题的InputFilter 实现,而是使用TextWatcher 和TextChangedListener 的TextChangedListener。
完整代码(示例)
editText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
super.afterTextChanged(editable);
String originalText = editable.toString();
int originalTextLength = originalText.length();
int currentSelection = editText.getSelectionStart();
// Create the filtered text
StringBuilder sb = new StringBuilder();
boolean hasChanged = false;
for (int i = 0; i < originalTextLength; i++) {
char currentChar = originalText.charAt(i);
if (isAllowed(currentChar)) {
sb.append(currentChar);
} else {
hasChanged = true;
if (currentSelection >= i) {
currentSelection--;
}
}
}
// If we filtered something, update the text and the cursor location
if (hasChanged) {
String newText = sb.toString();
editText.setText(newText);
editText.setSelection(currentSelection);
}
}
private boolean isAllowed(char c) {
// TODO: Add the filter logic here
return Character.isLetter(c) || Character.isSpaceChar(c);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do Nothing
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Do Nothing
}
});
InputFilter 在 Android 中不是一个好的解决方案的原因是它依赖于键盘实现。在将输入传递给EditText 之前,将过滤键盘输入。但是,由于某些键盘对InputFilter.filter() 调用有不同的实现,这是有问题的。
另一方面,TextWatcher 并不关心键盘的实现,它允许我们创建一个简单的解决方案并确保它适用于所有设备。
【讨论】:
onTextChanged 前面只需要一个public void。
可以使用setOnKeyListener。在这个方法中,我们可以自定义输入edittext!
【讨论】:
这就是我为编辑文本中的名称字段创建过滤器的方式。(第一个字母是大写字母,每个单词后只允许一个空格。
public void setNameFilter() {
InputFilter filter = new InputFilter() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (dend == 0) {
if (Character.isSpaceChar(source.charAt(i)) ||
!Character.isAlphabetic(source.charAt(i))) {
return Constants.Delimiter.BLANK;
} else {
return String.valueOf(source.charAt(i)).toUpperCase();
}
} else if (Character.isSpaceChar(source.charAt(i)) &&
String.valueOf(dest).endsWith(Constants.Delimiter.ONE_SPACE)) {
return Constants.Delimiter.BLANK;
} else if ((!Character.isSpaceChar(source.charAt(i)) &&
!Character.isAlphabetic(source.charAt(i)))) {
return Constants.Delimiter.BLANK;
}
}
return null;
}
};
editText.setFilters(new InputFilter[]{filter, new InputFilter.LengthFilter(Constants.Length.NAME_LENGTH)});
}
【讨论】:
我在 Kotlin 中也有同样的答案:
/**
* Returns the filter of the editText'es CharSequence value when [filterType] is:
* 1 -> letters; 2 -> letters and digits; 3 -> digits;
* 4 -> digits and dots
*/
class InputFilterAlphanumeric(private val filterType: Int): InputFilter {
override fun filter(source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence {
(source as? SpannableStringBuilder)?.let {sourceAsSpannableBuilder ->
for (i in (end - 1) downTo start) {
val currentChar = source[i]
when(filterType) {
1 -> {
if (!currentChar.isLetter() && !currentChar.isWhitespace()) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
2 -> {
if (!currentChar.isLetterOrDigit() && !currentChar.isWhitespace()) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
3 -> {
if (!currentChar.isDigit()) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
4 -> {
if (!currentChar.isDigit() || !currentChar.toString().contains(".")) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
}
}
return source
} ?: run {
val filteredStringBuilder = StringBuilder()
for (i in start until end) {
val currentChar = source?.get(i)
when(filterType) {
1 -> {
if (currentChar?.isLetter()!! || currentChar.isWhitespace()) {
filteredStringBuilder.append(currentChar)
}
}
2 -> {
if (currentChar?.isLetterOrDigit()!! || currentChar.isWhitespace()) {
filteredStringBuilder.append(currentChar)
}
}
3 -> {
if (currentChar?.isDigit()!!) {
filteredStringBuilder.append(currentChar)
}
}
4 -> {
if (currentChar?.isDigit()!! || currentChar.toString().contains(".")) {
filteredStringBuilder.append(currentChar)
}
}
}
}
return filteredStringBuilder
}
}
}
并通过扩展函数获取类:
fun EditText.filterByDataType(filterType: Int) {
this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}
【讨论】: