How do I use InputFilter to limit characters in an EditText in Android?

AndroidAndroid Edittext

Android Problem Overview


I want to restrict the chars to 0-9, a-z, A-Z and spacebar only. Setting inputtype I can limit to digits but I cannot figure out the ways of Inputfilter looking through the docs.

Android Solutions


Solution 1 - Android

I found this on another forum. Works like a champ.

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 });

Solution 2 - Android

InputFilters are a little complicated in Android versions that display dictionary suggestions. You sometimes get a SpannableStringBuilder, sometimes a plain String in the source parameter.

The following InputFilter should work. Feel free to improve this code!

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();
        }
	}
}

Solution 3 - Android

much easier:

<EditText
    android:inputType="text"
    android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />

Solution 4 - Android

None of posted answers did work for me. I came with my own solution:

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 });

Solution 5 - Android

Use this its work 100% your need and very simple.

<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />

In strings.xml

<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>

Solution 6 - Android

To avoid Special Characters in input type

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;
	}
};

You can set filter to your edit text like below

edtText.setFilters(new InputFilter[] { filter });

Solution 7 - Android

I have done something like this to keep it simple:

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 ]"), "")
    }
})

This way we are replacing all the unwanted characters in the new part of the source string with an empty string.

The edit_text variable is the EditText object we are referring to.

The code is written in kotlin.

Solution 8 - Android

In addition to the accepted answer, it is also possible to use e.g.: android:inputType="textCapCharacters" as an attribute of <EditText> in order to only accept upper case characters (and numbers).

Solution 9 - Android

It's Right, the best way to go about it to fix it in the XML Layout itself using:

<EditText
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />

as rightly pointed by Florian Fröhlich, it works well for text views even.

<TextView
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />

Just a word of caution, the characters mentioned in the android:digits will only be displayed, so just be careful not to miss any set of characters out :)

Solution 10 - Android

First add into strings.xml:

<string name="vin_code_mask">0123456789abcdefghjklmnprstuvwxyz</string>

XML:

android:digits="@string/vin_code_mask"

Code in 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
}

Strange, but it works weirdly on emulator's soft keyboard.

Warning! The following code will filter all letters and other symbols except digits for software keyboards. Only digital keyboard will appear on smartphones.

edit_text.keyListener = DigitsKeyListener.getInstance(context.getString(R.string.vin_code_mask))

I also usually set maxLength, filters, inputType.

Solution 11 - Android

For some reason the android.text.LoginFilter class's constructor is package-scoped, so you can't directly extend it (even though it would be identical to this code). But you can extend LoginFilter.UsernameFilterGeneric! Then you just have this:

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;
    }
}

This isn't really documented, but it's part of the core lib, and the source is straightforward. I've been using it for a while now, so far no problems, though I admit I haven't tried doing anything complex involving spannables.

Solution 12 - Android

This simple solution worked for me when I needed to prevent the user from entering empty strings into an EditText. You can of course add more characters:

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});

}

Solution 13 - Android

You can specify wanted characters in a regex and use it in InputFilter:

val regex = Regex("[a-zA-Z\\d ]")
    
editText.filters = arrayOf(InputFilter { source, _, _, _, _, _ ->
    source.filter { regex.matches(it.toString()) }
})

Notice, I didn't use \w character class, because it includes underscore _

Solution 14 - Android

This is an old thread, but the purposed solutions all have issues (depending on device / Android version / Keyboard).

DIFFERENT APPROACH

So eventually I went with a different approach, instead of using the InputFilter problematic implementation, I am using TextWatcher and the TextChangedListener of the EditText.

FULL CODE (EXAMPLE)

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
    }
});

The reason InputFilter is not a good solution in Android is since it depends on the keyboard implementation. The Keyboard input is being filtered before the input is passed to the EditText. But, because some keyboards have different implementations for the InputFilter.filter() invocation, this is problematic.

On the other hand TextWatcher does not care about the keyboard implementation, it allows us to create a simple solution and be sure it will work on all devices.

Solution 15 - Android

If you subclass InputFilter you can create your own InputFilter that would filter out any non-alpha-numeric characters.

The InputFilter Interface has one method, filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend), and it provides you with all the information you need to know about which characters were entered into the EditText it is assigned to.

Once you have created your own InputFilter, you can assign it to the EditText by calling setFilters(...).

http://developer.android.com/reference/android/text/InputFilter.html#filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int)

Solution 16 - Android

Ignoring the span stuff that other people have dealt with, to properly handle dictionary suggestions I found the following code works.

The source grows as the suggestion grows so we have to look at how many characters it's actually expecting us to replace before we return anything.

If we don't have any invalid characters, return null so that the default replacement occurs.

Otherwise we need to extract out the valid characters from the substring that's ACTUALLY going to be placed into the 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;
    } 
}; 

Solution 17 - Android

to prevent words in edittext. create a class that u could use anytime.

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;
	}
}

Solution 18 - Android

It is possible to use setOnKeyListener. In this method, we can customize the input edittext !

Solution 19 - Android

This is how I created filter for the Name field in Edit Text.(First letter is CAPS, and allow only single space after every word.

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)});
}

Solution 20 - Android

I have the same answer in 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
        }
    }
}

and get the class with an Extension function:

fun EditText.filterByDataType(filterType: Int) {
    this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTim WayneView Question on Stackoverflow
Solution 1 - AndroidmoonlightcheeseView Answer on Stackoverflow
Solution 2 - AndroidŁukasz SromekView Answer on Stackoverflow
Solution 3 - AndroidFlorian FröhlichView Answer on Stackoverflow
Solution 4 - AndroidKamil SewerynView Answer on Stackoverflow
Solution 5 - AndroidMohamed IbrahimView Answer on Stackoverflow
Solution 6 - Androiduser1414160View Answer on Stackoverflow
Solution 7 - AndroidLazarView Answer on Stackoverflow
Solution 8 - AndroidmblentonView Answer on Stackoverflow
Solution 9 - AndroidKailasView Answer on Stackoverflow
Solution 10 - AndroidCoolMindView Answer on Stackoverflow
Solution 11 - AndroidGroxxView Answer on Stackoverflow
Solution 12 - AndroidSwifty McSwiftertonView Answer on Stackoverflow
Solution 13 - AndroidYaroslav YermolenkoView Answer on Stackoverflow
Solution 14 - AndroidEyal BiranView Answer on Stackoverflow
Solution 15 - Androidnicholas.hauschildView Answer on Stackoverflow
Solution 16 - AndroidChristian WhitehouseView Answer on Stackoverflow
Solution 17 - AndroidSahar MillisView Answer on Stackoverflow
Solution 18 - AndroidVõ Hoài LênView Answer on Stackoverflow
Solution 19 - Androidu_pendraView Answer on Stackoverflow
Solution 20 - AndroidIrving KennedyView Answer on Stackoverflow