I'm trying to implement an EditText that limits input to alpha chars only [A-Za-z].
I started with the InputFilter method from this post. When I type "a%" the text disappears then if I hit backspace the text is "a". I've tried other variations on the filter function like using a regex to match only [A-Za-z] and sometimes see crazy behavior like repeating chars, I'll type "a" then "b" and get "aab" then type "c" and get "aabaabc" then hit backspace and get "aabaabcaabaabc"!
Here's the code I'm working with so far with the different approaches I've tried.
EditText input = (EditText)findViewById( R.id.inputText );
InputFilter filter = new InputFilter() {
#Override
public CharSequence filter( CharSequence source, int start, int end, Spanned dest, int dstart, int dend ) {
//String data = source.toString();
//String ret = null;
/*
boolean isValid = data.matches( "[A-Za-z]" );
if( isValid ) {
ret = null;
}
else {
ret = data.replaceAll( "[##$%^&*]", "" );
}
*/
/*
dest = new SpannableStringBuilder();
ret = data.replaceAll( "[##$%^&*]", "" );
return ret;
*/
for( int i = start; i < end; i++ ) {
if( !Character.isLetter( source.charAt( i ) ) ) {
return "";
}
}
return null;
}
};
input.setFilters( new InputFilter[]{ filter } );
I'm totally stumped on this one so any help here would be greatly appreciated.
EDIT:
Ok, I've done quite a lot of experimenting with InputFilter and have drawn some conclusions, albeit no solution to the problem. See the comments in my code below. I'm going to try Imran Rana's solution now.
EditText input = (EditText)findViewById( R.id.inputText );
InputFilter filter = new InputFilter() {
// It is not clear what this function should return!
// Docs say return null to allow the new char(s) and return "" to disallow
// but the behavior when returning "" is inconsistent.
//
// The source parameter is a SpannableStringBuilder if 1 char is entered but it
// equals the whole string from the EditText.
// If more than one char is entered (as is the case with some keyboards that auto insert
// a space after certain chars) then the source param is a CharSequence and equals only
// the new chars.
#Override
public CharSequence filter( CharSequence source, int start, int end, Spanned dest, int dstart, int dend ) {
String data = source.toString().substring( start, end );
String retData = null;
boolean isValid = data.matches( "[A-Za-z]+" );
if( !isValid ) {
if( source instanceof SpannableStringBuilder ) {
// This works until the next char is evaluated then you get repeats
// (Enter "a" then "^" gives "a". Then enter "b" gives "aab")
retData = data.replaceAll( "[##$%^&*']", "" );
// If I instead always returns an empty string here then the EditText is blanked.
// (Enter "a" then "^" gives "")
//retData = "";
}
else { // source is instanceof CharSequence
// We only get here if more than 1 char was entered (like "& ").
// And again, this works until the next char is evaluated then you get repeats
// (Enter "a" then "& " gives "a". Then enter "b" gives "aab")
retData = "";
}
}
return retData;
}
};
input.setFilters( new InputFilter[]{ filter } );
Use the following code:
EditText input = (EditText) findViewById(R.id.inputText);
input.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
for( int i = start;i<s.toString().length(); i++ ) {
if( !Character.isLetter(s.charAt( i ) ) ) {
input.setText("");
}
}
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
If you want the valid text to remain in the EditText:
input.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
for( int i = 0;i<s.toString().length(); i++ ) {
if( !Character.isLetter(s.charAt( i ) ) ) {
s.replace(i, i+1,"");
}
}
}
});
Fix for repeating text, work on all Android Versions:
public static InputFilter getOnlyCharactersFilter() {
return getCustomInputFilter(true, false, false);
}
public static InputFilter getCharactersAndDigitsFilter() {
return getCustomInputFilter(true, true, false);
}
public static InputFilter getCustomInputFilter(final boolean allowCharacters, final boolean allowDigits, final boolean allowSpaceChar) {
return 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)) {
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) {
if (Character.isLetter(c) && allowCharacters) {
return true;
}
if (Character.isDigit(c) && allowDigits) {
return true;
}
if (Character.isSpaceChar(c) && allowSpaceChar) {
return true;
}
return false;
}
};
}
Now you can use this filer like:
//Accept Characters Only
edit_text.setFilters(new InputFilter[]{getOnlyCharactersFilter()});
//Accept Digits and Characters
edit_text.setFilters(new InputFilter[]{getCharactersAndDigitsFilter()});
//Accept Digits and Characters and SpaceBar
edit_text.setFilters(new InputFilter[]{getCustomInputFilter(true,true,true)});
Bingo, I found the problem!
When I use android:cursorVisible="false" on the EditText the start and dstart parameters don't match up correctly.
The start parameter is still always 0 for me, but the dstart parameter is also always 0 so it works out as long as I use .replaceAll(). This is contrary to what this post says so I don't quite understand why but at least I can build something that works now!
We had a similar problem and I believe a solution[0] that would work for you as well. Our requirements were to implement an EditText that stripped rich text input. For example, if the user copied bold text to their clipboard and pasted it into the EditText, the EditText should remove the bold emphasis styling and preserve only the plain text.
The solution class looks something like this:
public class PlainEditText extends EditText {
public PlainEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
addFilter(this, new PlainTextInputFilter());
}
private void addFilter(TextView textView, InputFilter filter) {
InputFilter[] filters = textView.getFilters();
InputFilter[] newFilters = Arrays.copyOf(filters, filters.length + 1);
newFilters[filters.length] = filter;
textView.setFilters(newFilters);
}
private static class PlainTextInputFilter implements InputFilter {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
int dstart, int dend) {
return stripRichText(source, start, end);
}
private CharSequence stripRichText(CharSequence str, int start, int end) {
// ...
}
}
}
Our original implementation for stripRichText() was simple:
// -- BROKEN. DO NOT USE --
String plainText = str.subSequence(start, end).toString();
return plainText;
The Java base String class doesn't retain any styling information so converting the CharSequence interface to a concrete String copies only plain text.
What we didn't realize was that some Android soft keyboards add and depend on temporary compositional hints for typos and other things. The problem manifests by removing the hints as well as repeating characters in an unexpected way (usually doubling the entire EditText field's input). The documentation[1] for InputFilter.filter() communicates the requirement this way:
* Note: If <var>source</var> is an instance of {#link Spanned} or
* {#link Spannable}, the span objects in the <var>source</var> should be
* copied into the filtered result (i.e. the non-null return value).
I believe the proper solution is to preserve temporary spans:
/** Strips all rich text except spans used to provide compositional hints. */
private CharSequence stripRichText(CharSequence str, int start, int end) {
String plainText = str.subSequence(start, end).toString();
SpannableString ret = new SpannableString(plainText);
if (str instanceof Spanned) {
List<Object> keyboardHintSpans = getComposingSpans((Spanned) str, start, end);
copySpans((Spanned) str, ret, keyboardHintSpans);
}
return ret;
}
/**
* #return Temporary spans, often applied by the keyboard to provide hints such as typos.
*
* #see {#link android.view.inputmethod.BaseInputConnection#removeComposingSpans}
* #see {#link android.inputmethod.latin.inputlogic.InputLogic#setComposingTextInternalWithBackgroundColor}
*/
#NonNull private List<Object> getComposingSpans(#NonNull Spanned spanned,
int start,
int end) {
// TODO: replace with Apache CollectionUtils.filter().
List<Object> ret = new ArrayList<>();
for (Object span : getSpans(spanned, start, end)) {
if (isComposingSpan(spanned, span)) {
ret.add(span);
}
}
return ret;
}
private Object[] getSpans(#NonNull Spanned spanned, int start, int end) {
Class<Object> anyType = Object.class;
return spanned.getSpans(start, end, anyType);
}
private boolean isComposingSpan(#NonNull Spanned spanned, Object span) {
return isFlaggedSpan(spanned, span, Spanned.SPAN_COMPOSING);
}
private boolean isFlaggedSpan(#NonNull Spanned spanned, Object span, int flags) {
return (spanned.getSpanFlags(span) & flags) == flags;
}
/**
* Apply only the spans from src to dst specific by spans.
*
* #see {#link android.text.TextUtils#copySpansFrom}
*/
public static void copySpans(#NonNull Spanned src,
#NonNull Spannable dst,
#NonNull Collection<Object> spans) {
for (Object span : spans) {
int start = src.getSpanStart(span);
int end = src.getSpanEnd(span);
int flags = src.getSpanFlags(span);
dst.setSpan(span, start, end, flags);
}
}
[0] Actual implementation available here: https://github.com/wikimedia/apps-android-wikipedia/blob/e9ddd8854ff15cde791a2e6fb7754a5450d6f7cf/app/src/main/java/org/wikipedia/richtext/RichTextUtil.java
[1] https://android.googlesource.com/platform/frameworks/base/+/029942f77d05ed3d20256403652b220c83dad6e1/core/java/android/text/InputFilter.java#37
I would just like to add my solution to the problem(as late as it is). I found that if you add
yourEditText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
Then the backspace problems stop
Related
In my application I want use EditText and I want start characters just English alphabet.
My mean is, First of characters has just English alphabet (a to z).
I write below codes :
registerUsernameEdtTxt.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (charSequence.toString().length() < 2) {
registerUsernameEdtTxt.setFilters(new InputFilter[]{new InputFilter() {
public CharSequence filter(CharSequence src, int start,
int end, Spanned dst, int dstart, int dend) {
if (src.toString().matches("[a-zA-Z ]+")) {
registerUsernameInptLay.setErrorEnabled(false);
return src;
}
registerUsernameInptLay.setError(context.getResources().getString(R.string.insertJustEnglish));
return "";
}
}});
}
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void afterTextChanged(Editable editable) {
}
});
But not work me! How can I it?
Please help me
Try this:
EditText et = findViewById(R.id.text_field);
// This part is to keep the existing filters of the EditText.
InputFilter[] filters = et.getFilters();
InputFilter[] newFilters = Arrays.copyOf(filters, filters.length + 1);
InputFilter firstFilter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source != null && source.length() > 0 && dstart == 0){
if (!source.toString().matches("^[A-Za-z].*"))
return "";
}
return null;
}
};
// Add the filter to the array of filters
newFilters[newFilters.length - 1] = firstFilter;
et.setFilters(newFilters);
Can be simplified like this (if the previous InputFilter are not required)
EditText et = findViewById(R.id.text_field);
InputFilter firstFilter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source != null && source.length() > 0 && dstart == 0){
if (!source.toString().matches("^[A-Za-z].*"))
return "";
}
return null;
}
};
et.setFilters(new InputFilter[]{firstFilter});
EDIT
If you want to keep the rest of the string (for example if the user pastes the text):
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source != null && source.length() > 0 && dstart == 0) {
String s = source.toString();
if (!s.matches("^[A-Za-z].*")) {
Toast.makeText(getApplicationContext(), "This is a Toast", Toast.LENGTH_SHORT).show();
return s.substring(1, s.length());
}
}
return null;
}
EDIT 2
The above versions don't work on deletion or when a text is pasted with more than a forbidden char at the beginning (e.g. '88sdfs') as only the first one was removed and the rest kept.
This new version should cover all these cases.
I'd suggest to create a separated class for the InputFilter.
InputFilter firstFilter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (dstart != 0) { // The modified part is not beginning of the text
return null; // Nothing need to be changed
}
if (source.length() > 0) { // text is added
return onTextAdded(source.toString());
} else { // text is removed
return onTextRemoved(dest, dend);
}
}
private CharSequence onTextRemoved(Spanned dest, int dend) {
// check what the string will look like after the text being removed
String substring = dest.toString().substring(dend, dest.length());
// if there is still a string and it's not valid
if (substring.length() > 0 && !isValid(substring)) {
displayError();
// return the deleted part for the string to not change
return dest.subSequence(0, dend);
}
return null;
}
private String onTextAdded(String s) {
if (isValid(s)) {
return null;
} else {
String substring;
// We want to keep a part of the added string (it can be a paste).
// so we remove all the first characters as long as the string doesn't match
// the requirements
for (int i = 1; i < s.length(); i++) {
substring = s.substring(i, s.length());
if (isValid(substring))
break;
}
displayError();
return substring;
}
}
private boolean isValid(String s) {
return s.matches("^[A-Za-z].*");
}
private void displayError() {
Toast.makeText(getApplicationContext(), "This is a Toast", Toast.LENGTH_SHORT).show();
}
};
et.setFilters(new InputFilter[]{firstFilter});
Add this class to your project:
public class EnglishInputFilter implements InputFilter {
#Override
public CharSequence filter(CharSequence charSequence, int start, int end, Spanned spanned, int dstart, int dend) {
StringBuilder newChars = new StringBuilder(charSequence.toString().substring(start, end));
for (int i = 0; i < newChars.length(); ) {
if (!Character.isLetter(newChars.charAt(i)))
newChars.deleteCharAt(i);
else
i++;
}
return newChars.toString();
}
}
Then do this with your EditText:
myEditText.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)
myEditText.setFilters(new InputFilter[]{new EnglishInputFilter()});
It also removes no letter characters from pasted strings, if you paste "1A2B" it will really paste "AB"
You can add more filters, for example for limit the total length.
If you want that your edit text should accept starting first character with any English alphabet Then you can use regular expression like;
String regexp = "^([a-zA-Z]+).*$";
Pattern pattern = Pattern.compile(regexp);
boolean ismatches = pattern.matcher("your input that start with the alphabet").matches();
if(ismatches)
do your stuff
else
show error
Hey guys I'm developing an application for Market Transactions and stuff, and the client wants to have a condition on the edit text of type number decimal.
He wants the user to enter only number 5 after the dot if the number is a decimal and only one digit after the dot.
i.e.
15
14
1949
12.33 (not accepted)
12.5 (accepted)
so how to do so please give me some hints
try this and check whether it works.
final String regex = "^\\-?(\\d{0,5}|\\d{0,5}\\.[5]{0,1})$";
((EditText)rootView.findViewById(R.id.editText1)).setFilters(new InputFilter[] {
new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
if (end > start) {
// adding: filter
// build the resulting text
String destinationString = destination.toString();
String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
// return null to accept the input or empty to reject it
return resultingTxt.matches(regex) ? null : "";
}
// removing: always accept
return null;
}
}
});
Here user input is checked to match the regular expression and return the input string if it matches and null if not.
<Edittext
android:id="#+id/testing"
android:inputType="numberDecimal"
android:digits="0123456789."
>
</Edittext>
Then, use InputFilter
testing.setFilters(new InputFilter[]{NumberFilter(), new InputFilter.LengthFilter(6)});
//OR
testing.setFilters(new InputFilter[]{NumberFilter()});
Create class for NumberFilter implemenets InputFilter
public class NumberFilter implements InputFilter{
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// ignore empty space and not number
if (!isNullorEmpty(source.toString()) && !isOnlyNumber(source.toString()))
return "";
//ignore first .
if (!source.toString().charAt(0).equals("."))
return "";
if ((source.toString().charAt(0) != '8' || source.toString().charAt(0) != '9'))
return "";
return null;
}
}
// to allow 1 and 1.2
public static boolean isOnlyNumber(String number) {
return number.matches("(?<=^| )\d+(\.\d+)?(?=$| )");
}
//check empty space or Null
public static boolean isNullorEmpty(String string){
return StringUtils.isEmpty(string);
}
Try this addTextChangedListener.
You need to append 5 to the editText whenever user inputs a dot.
`flag =0;
_field.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s.toString().contains(".") && (flag == 0)) {
flag = 1;
_field.setText(_field.getText() + "5");
} else if (s.toString().contains(".") && (flag == 1)) {
} else {
flag = 0;
}
}
});`
I have a problem while inserting special characters: single quote, double quote and emojis into the database from editText.
I want my editText to restrict those characters, and I was successful in restricting emojis, but I failed to restrict users entering single quote and double quote.
E.g. When I try to enter text Today's List from editText into the database it generates an exception.
I have used InputFilter in editText to filter emojis, and I want this filter to restrict single quote and double quotes too.
public static InputFilter getEditTextFilterEmoji() {
return new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
CharSequence sourceOriginal = source;
source = replaceEmoji(source);
end = source.toString().length();
if (end == 0)
return ""; //Return empty string if the input character is already removed
if (!sourceOriginal.toString().equals(source.toString())) {
char[] v = new char[end - start];
TextUtils.getChars(source, start, end, v, 0);
String s = new String(v);
if (source instanceof Spanned) {
SpannableString sp = new SpannableString(s);
TextUtils.copySpansFrom((Spanned) source, start, end, null, sp, 0);
return sp;
} else {
return s;
}
} else {
return null; // keep original
}
}
private String replaceEmoji(CharSequence source) {
String notAllowedCharactersRegex = "[^a-zA-Z0-9##\\$%\\&\\-\\+\\(\\)\\*;:!\\?\\~`£\\{\\}\\[\\]=\\.,_/\\\\\\s'\\\"<>\\^\\|÷×]";
return source.toString()
.replaceAll(notAllowedCharactersRegex, "");
}
};
}
Can anyone help me with this ?
Restrict the EditText to use given digits only.
<EditText
........
android:inputType="textPersonName"
android:digits="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY zZ0123456789"
/>
As per my understanding all emoji contains /u so I used it like this
public static InputFilter[] getEmojiFilter(String blockChars) {
return new InputFilter[]{(source, start, end, dest, dstart, dend) -> {
String source1= StringEscapeUtils.escapeJava(source.toString());
for (int i = start; i < end; i++) {
if (source != null && blockChars.contains("" + source1.charAt(i))) {
return source.subSequence(start, i);
}
}
return null;
}};
}
and Write below line for Edittext
editext.setFilters(getEmojiFilter("'\"\\//\\u"));
If you want alphabets only in edittext, Add this line in edittext tag
android:digits="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Try this one....worked for me
private EditText InputText;
private String blockCharacterSet = "~#^|$%&*!"; //Special characters to block
private InputFilter filter = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source != null && blockCharacterSet.contains(("" + source))) {
return "";
}
return null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InputText = (EditText) findViewById(R.id.InputText);
InputText.setFilters(new InputFilter[] { filter });
}
Add This in Strings.xml. It's allow u to enter alphanumeric and space also.
<string name="charset">0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY Z</string>
This answer worked for me. I searched different questions and I got my answer.
setFilters(new InputFilter[]{new EmojiExcludeFilter()});
private class EmojiExcludeFilter implements InputFilter {
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String specialChars = "/*!##$%^&*()\"{}_[]|\\?/<>,.:-'';§£¥...";
for (int i = start; i < end; i++) {
int type = Character.getType(source.charAt(i));
if (type == Character.SURROGATE || type == Character.OTHER_SYMBOL || type == Character.MATH_SYMBOL || specialChars.contains("" + source)|| Character.isWhitespace(0)) {
return "";
}
}
return null;
}
}
I have an Edittext in my android application. I don't want to allow user to enter first space character..but after entering other charecter user can enter space also..I used
<EditText
android:id="#+id/editText1_in_row"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:digits="_,qwertzuiopasdfghjklyxcvbnm,QWERTYUIOPASDFGHJKLZXCVBNM,0123456789">
but in this case user can not enter space.
I have also used Text Watcher but I need not to allow user at the time of entering text as
android:digits works.
final EditText editText = (EditText)findViewById(R.id.editText1_in_row);
InputFilter filter = new InputFilter() {
boolean canEnterSpace = false;
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if(editText.getText().toString().equals(""))
{
canEnterSpace = false;
}
StringBuilder builder = new StringBuilder();
for (int i = start; i < end; i++) {
char currentChar = source.charAt(i);
if (Character.isLetterOrDigit(currentChar) || currentChar == '_') {
builder.append(currentChar);
canEnterSpace = true;
}
if(Character.isWhitespace(currentChar) && canEnterSpace) {
builder.append(currentChar);
}
}
return builder.toString();
}
};
editText.setFilters(new InputFilter[]{filter});
and remove this property from your EditText
android:digits="_,qwertzuiopasdfghjklyxcvbnm,QWERTYUIOPASDFGHJKLZXCVBNM,0123456789"
This code works exactly according to your needs.
Using InputFilter easy to handle enter first white space character ignore
First setFilters() method on editText
editText.setFilters(new InputFilter[]{ignoreFirstWhiteSpace()});
Make InputFilter
// ignore enter First space on edittext
public InputFilter ignoreFirstWhiteSpace() {
return 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.isWhitespace(source.charAt(i))) {
if (dstart == 0)
return "";
}
}
return null;
}
};
}
No need to write android:digits property on XML
remove this line
android:digits="_,qwertzuiopasdfghjklyxcvbnm,QWERTYUIOPASDFGHJKLZXCVBNM,0123456789"
Simply restrict the user to type space as others said on start only:
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String text = createPL.getText().toString();
//restrict space for first char
if (text.startsWith(" ")) {
edittext.setText(text.trim());
}
}
Use this. If the character at starting Position is a space, set textView Text To blank
editText1_in_row.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length()>0 && s.subSequence(0, 1).toString().equalsIgnoreCase(" ")) {
editText1_in_row.setText(""); }
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
This works for me
android:inputType="textPersonName"
android:digits= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_-!##$%^*()"
why cant you use editText.getText().trim(); function while using the EditText data
If you want to filter input characters in your EditText, you need to use InputFilter. Here is example.
//Allow only letters or digits
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;
}
};
EditText text = (EditText)findViewById(R.id.edittext1);
text.setFilters(new InputFilter[]{filter});
For details look here
A slight variation on https://stackoverflow.com/users/2868352/abhishek-v answer.
public class NoInitialSpaceFilter implements InputFilter {
#Override
public CharSequence filter(final CharSequence source, final int start, final int end, final Spanned dest, final int dstart, final int dend) {
if (dstart == 0) {
for (int i = start; i < end; i++) {
if (Character.isSpaceChar(source.charAt(i))) {
return "";
}
}
}
return null;
}
}
Usage:
editText.setFilters(new InputFilter[]{new NoInitialSpaceFilter});
android:digits="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890.,_-!##$()+=><:;?"
This is filter I have used for Name validation in EditText. First letter CAPS, not space and special character. After completing the word not allow more than a single space.
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)});
}
here is kotlin extension
// ignore enter First space on edittext
fun EditText.filterFirstSpace() {
val initSpaceFilter: InputFilter = object : InputFilter {
var canEnterSpace = false
override fun filter(
source: CharSequence, start: Int, end: Int,
dest: Spanned, dstart: Int, dend: Int,
): CharSequence {
if (this#filterFirstSpace.text.toString() == "") {
canEnterSpace = false
}
val builder = StringBuilder()
for (i in start until end) {
val currentChar = source[i]
if (Character.isLetterOrDigit(currentChar) || currentChar == '_') {
builder.append(currentChar)
canEnterSpace = true
}
if (Character.isWhitespace(currentChar) && canEnterSpace) {
builder.append(currentChar)
}
}
return builder.toString()
}
}
filters = arrayOf(initSpaceFilter)
}
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.
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 });
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();
}
}
}
much easier:
<EditText
android:inputType="text"
android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />
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 });
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>
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 });
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.
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.
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).
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 :)
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.
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 _
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});
}
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.
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)
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;
}
};
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;
}
}
It is possible to use setOnKeyListener. In this method, we can customize the input edittext !
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)});
}
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))
}