Hot questions for Using Android EditText in filter

Question:

This is my xml

<EditText
android:id="@+id/et_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textVisiblePassword"
android:hint="Provide comments here..."
android:gravity="top"
android:maxLength="5"
android:textSize="12sp"
android:visibility="visible"
/>

Neither is it working using this code

TextView editEntryView = new TextView(...);
InputFilter[] filterArray = new InputFilter[1];
filterArray[0] = new InputFilter.LengthFilter(5);
editEntryView.setFilters(filterArray);

maxLenth is not working, I dont know why, but it isnt. I have checked other answers on the stack but they are also not working. Please check if any of EditText attributes are conflicting or what is the problem?

EDIT: Same problem is being faced by other developers See comments here same problem is being faced by Mansi and aat And here in comments same problem is being faced by Vincy and Riser

EDIT: Problem solved I was using input filter which overrides the max length in xml making it not able to work. The reason input filter didn't worked for me was that I was using another input filter which overwrites the previous maxLength input filter. Making it into a single input filter fixed that issue for me.


Answer:

Try this, it will work for both maxlenght and input filter

month.setFilters(new InputFilter[]{new InputFilterMinMax("0", "12"), new InputFilter.LengthFilter(2)});

Question:

In this code I have search multiple text ex. I have search sachin.

sachin is show the list but click to back sachin to sac not display to sa list on adapter. How to solve it without any library?

when I press back space and remove a char this time dos not list not display. Example

Suppose I have search sachin to text change sachin to sac. In this case not display sa list. I have clear all list that case display all list. search sa show the list sachin and sardar now search sac now display the sachin search only sac to sc that's time display only sachin not disply the sardar in the list

My Adapter

private class ItemFilter extends Filter {
    protected FilterResults performFiltering(CharSequence constraint) {

        FilterResults results = new FilterResults();

        if (constraint != null && constraint.length() > 0) {
            ArrayList<Build> buildlist = new ArrayList<Build>();


            for (int i = 0; i < buildList.size(); i++) {
                if ((buildList.get(i).getName().toUpperCase())
                        .contains(constraint.toString().toUpperCase())) {

                    Build babydata = new Build(buildList.get(i).getImages(), buildList.get(i).getName());

                    buildlist.add(babydata);
                }
            }
            results.count = buildlist.size();
            results.values = buildlist;

        } else {
            results.count = buildList.size();
            results.values = buildList;
        }
        return results;

    }

    @Override
    protected void publishResults(CharSequence constraint,
                                  FilterResults results) {
        buildList = (ArrayList<Build>) results.values;
        notifyDataSetChanged();
    }
}

Activity class

 EditText editTxt = (EditText) findViewById(R.id.search);
    editTxt.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

            if (s.length() <= 0) {
                Log.d("jay", "s.length() <= 0" + s.toString());
                buildList.clear();
                buildList.addAll(buildListCopy);
                recyclerView.setAdapter(null);
                buildCustomAdapter = new BuildCustomAdapter(buildList);
                recyclerView.setAdapter(buildCustomAdapter);

            } else {
                buildCustomAdapter.getFilter().filter(s.toString());
            }
            Log.d("jay", "mobisharnam" + s.toString());
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    });

Answer:

Without any Library simple logic Finally I have solution in this question

In your Adapter Constructor add the new copy list

After the copy list is add in filter

 private List<YourModel> modelList;
 private List<YourModel> modelListCopy;
 private ItemFilter mFilter = new ItemFilter();


 public YourAdapter(List<YourModel> modelList) {
    this.modelList= modelList;
    this.modelListCopy= new ArrayList<>();
    modelListCopy.addAll(modelList);
}
private class ItemFilter extends Filter {

    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();

        if (constraint != null && constraint.length() > 0) {
            List<YourModel> filterList = new ArrayList<YourModel>();

            for (int i = 0; i < modelListCopy.size(); i++) {
                if ((modelListCopy.get(i).getName().toUpperCase())
                        .contains(constraint.toString().toUpperCase())) {
                    YourModel builddata = new YourModel(modelListCopy.get(i).getImages(), modelListCopy.get(i).getName());
                    filterList.add(builddata);
                }
            }
            results.count = filterList.size();
            results.values = filterList;

        } else {
            results.count = modelListCopy.size();
            results.values = modelListCopy;
        }
        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint,
                                  FilterResults results) {
        modelList= (ArrayList<YourModel>) results.values;
        notifyDataSetChanged();
    }

Activity Class

like this

 CustomAdapter youradapter= new CustomAdapter(modelList);

Question:

I am trying to create a regex for my EditText to only allow input that is in dollar format. However it is not working.

public class DecimalInputFilter implements InputFilter {

    Pattern mPattern;

    public DecimalInputFilter() {
        mPattern=Pattern.compile("^[0-9]+([.][0-9]{2})?$");
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

        Matcher matcher=mPattern.matcher(dest);
        if(!matcher.matches())
            return "";
        return null;
    }

}

The Regex thought process -

  • At least one numeric character
  • a dot followed by exactly two numeric characters (Optional)

When I try to apply this, it does not allow me to input any numbers. What am I missing?


Answer:

Use the next filter function:

public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    if (source.equals("")) return null; // Para el backspace
    StringBuilder builder = new StringBuilder(dest);
    builder.replace(dstart, dend, source.subSequence(start, end).toString());
    Matcher matcher=mPattern.matcher(builder);
    if(!matcher.matches())
        return "";
    return null;
}

Because if you match on builder it will let you know if the final string matches the proposed expression, otherwise it returns the empty string.

Question:

I have EditText, I use it to enter percentage value. I put restrict that user can not enter value more than 100 and it's works fine. I'm also allowed to enter fraction part in percentage, But allow only two digit after decimal point (.) i.e. 99.95

I want it to achieve programmatically because I use this EditText in the popup that uses every time to enter value and change in other field. I have tried following code to achieve my thing.

if (title.contains("Deposit")) {
    edt_get_value_popup_value.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);
    edt_get_value_popup_value.setFilters(new InputFilter[]{new InputFilterMinMax("1", "100")});
}

I'm using filter class to convert into percentage, see following code:

public class InputFilterMinMax implements InputFilter {

   private Float min, max;

   public InputFilterMinMax(Float min, Float max) {
        this.min = min;
        this.max = max;
   }

   public InputFilterMinMax(String min, String max) {
        this.min = Float.parseFloat(min);
        this.max = Float.parseFloat(max);
    }

   @Override
   public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
       try {
            Float input = Float.parseFloat(dest.toString() + source.toString());
            if (isInRange(min, max, input)) return null;
        } catch (NumberFormatException nfe) {
        }
        return "";
   }

   private boolean isInRange(Float a, Float b, Float c) {
        return b > a ? c >= a && c <= b : c >= b && c <= a;
   }
}

How can I set limit of fraction part in EditText?


Answer:

you can use input filter as below after applying some changes:

 public class InputFilterMinMax implements InputFilter {

    private Float min, max;

    public InputFilterMinMax(Float min, Float max) {
        this.min = min;
        this.max = max;
    }

    public InputFilterMinMax(String min, String max) {
        this.min = Float.parseFloat(min);
        this.max = Float.parseFloat(max);
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        try {
            Float input = Float.parseFloat(dest.toString() + source.toString());
            String inputValue = (dest.toString() + source.toString());
            if (isInRange(min, max, input, inputValue)) return null;
        } catch (NumberFormatException nfe) {
        }
        return "";
    }

    private boolean isInRange(Float min, Float max, Float input, String inputValue) {
        if (inputValue.contains(".") && (inputValue.split("\\.").length > 1)) {
            return (max > min ? input >= min && input <= max : input >= max && input <= min) && (inputValue.split("\\.")[1].length() < 3);
        } else {
            return (max > min ? input >= min && input <= max : input >= max && input <= min);
        }
    }
}

Question:

So i'm working on a WhatsApp like verification system where user inputs the code received via sms and code is sent back to the server..yada yada ..all that basic stuff.

My dilemma is that i have received and read the sms correctly. How do i filter the body so that that it passes the number (not phone number but verification code) to the editText automatically. I'm trying to avoid users having to enter the verification code manually. Lemme show some code below.

public void processReceive(Context context, Intent intent){

    Bundle bundle = intent.getExtras();
    if(bundle == null){
        return;
    }

    Object[] objectArray = (Object[])bundle.get("pdus");

    for(int i = 0; i < objectArray.length; i++){
        SmsMessage smsMsg = SmsMessage.createFromPdu((byte[])objectArray[i]);
        String smsBody = smsMsg.getMessageBody();

        Toast.makeText(context, smsBody, Toast.LENGTH_SHORT).show();
    }

}

//In the code above, my broadcastReceiver receives the sms and i can display the body in a toast. The sms goes something like this: "Your verification code: 12345".

How do i get just the code from the sms and send its value to and editText programmatically like WhatsApp does.

number = (EditText) findViewById(R.id.number);

Thank you. You input is greatly appreciated


Answer:

Try this it may be help to you

public static String GENERAL_OTP_TEMPLATE = "Your verification code: (.*).";

SmsMessage[] message = new SmsMessage[objectArray.length];
for (int i = 0; i < objectArray.length; i++) {
    message[i] = SmsMessage.createFromPdu((byte[]) objectArray[i]);

}
Pattern generalOtpPattern = Pattern.compile(GENERAL_OTP_TEMPLATE);
Matcher generalOtpMatcher = generalOtpPattern.matcher(message[0].getMessageBody().toString());

if (generalOtpMatcher.find()) {
       String otp = generalOtpMatcher.group(1);
       number.setText(otp);
}

Question:

I'm developing an app for Android using Android Studio. I have to let the user insert a text into an EditText with a maximum length. For this aim I have employed a lengthFilter passing to it the maximum length.

Here the declaration:

etMessage.setFilters(new InputFilter[] {new InputFilter.LengthFilter(maxMessageLength)});

In another thread I execute the following code:

while (!startEncoding){

    final String temp = etMessage.getText().toString();

    if (!(Comparison.equals(temp))) {
        Comparison = temp;
        handler.post(new Runnable() {
            @Override
            public void run() {
                tvNumCharacters.setText(Integer.toString(maxMessageLength - etMessage.length()));
            }
        });
    }
}

These last lines just show into a TextView (tvNumCharacters) the residual numbers of characters the user can input when the string inside the EditText (temp) is different from the string previously contained in the EditText (Compare).

The Problem is: when the user deletes some characters (independetly from the actual length of the already inserted string) the following exception is raised:

AndroidRuntime: FATAL EXCEPTION: Thread-8364
Process: com.user.steganography, PID: 12057
java.lang.IndexOutOfBoundsException: getChars (0 ... 16) ends beyond length 15
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1090)
at android.text.SpannableStringBuilder.getChars(SpannableStringBuilder.java:972)
at android.text.SpannableStringBuilder.toString(SpannableStringBuilder.java:994)
at com.user.steganography.Coding.checkTextLength(Coding.java:111)
at com.user.steganography.Coding.access$000(Coding.java:19)
at com.user.steganography.Coding$2.run(Coding.java:84)
at java.lang.Thread.run(Thread.java:818)

Sometimes it crashes when deleting just one character, other only when deleting more characters.

This happens when etMessage.getText().toString() is recalled.

Could anyone suggest me a solution for this problem? I have already tried to change the attribute android:inputType but it still not work.


Answer:

You have threading issues. The contents of etMessage are changed before they are read the second time.

Question:

I need to block the user from inputing the . (period) character from the keyboard on a number EditText, but I need to be able to use it on the same EditText via the setText method.

I've tried using InputFilter but when I call setText the . character don't show. I've also tried setting the digits parameter in the xml but the setText doesn't work either.

Is there a way to do this?

Here's my InputFilter code:

public static InputFilter blockPeriod(){

    return new InputFilter() {
      @Override
      public CharSequence filter(CharSequence charSequence, int i, int i1, Spanned spanned, int i2, int i3) {

          for (int j = i; j <i1 ; j++) {

              char c = charSequence.charAt(j);
              if (!allowed(c)){

                  return "";

              }

          }

          return null;
      }

      private boolean allowed(char c){

          return c != '.';

      }

  };

}

Answer:

You can do it with your InputFilter, but you need to allow it for a while when you calling setText() method.

private static class AllowableInputFilter implements InputFilter {
    private boolean mAllowDot;

    public void setAllowDot(boolean toAllow) {
      mAllowDot = toAllow;
    }

    ....


    private boolean allowed(char c){
      return mAllowDot || c != '.';
    }
}

public void forceText(String text) {
  mInputFilter.setAllowDot(true);
  mEditText.setText(text);
  mInputFilter.setAllowDot(false);
}

mInputFilter = new AllowableInputFilter();
mInputFilter.setAllowDot(false);

mEditText.setFilters(new InputFilter[] {mInputFilter});

forceText("Okaaayy....");

Question:

I have a text field where the start symbol is $ (could be euro or pound depending on an application setting). I need to make it so that if the user clicks before the symbol nothing will happen. In other words, the selection must remain after the symbol. I tried doing something like this but it seems wrong and it gave me an error:

billAmount.addTextChangedListener(new TextWatcher() {

    //other methods 

    @Override
    public void afterTextChanged(Editable s) {
        billAmount.setText(currencySymbol + billAmount.getText().toString());
    }
});

I was thinking of using an inputFilter but nothing I tried worked. I'm also not allowed to use a TextView right before the EditText.


Answer:

First, in your code sample, the reason you are getting an error is because, as others have said, you are calling the setText method inside the afterTextChanged method. Calling setText is obviously changing the text which causes afterTextChanged to be called again. This results in the afterTextChanged being called continuously until there is eventually a stack overflow.

You have two issues: 1) You want to always keep the cursor positioned after the currency symbol, and 2) You want to make sure the currency symbol is never somehow removed.

The easiest way to solve #1 is to create a subclass of EditText and override the onSelectionChanged method.

public class MyEditText extends EditText {

    // ...

    @Override
    public void onSelectionChanged(int selStart, int selEnd) {
        super.onSelectionChanged(selStart, selEnd);

        // Make sure the text's length is greater than zero.
        // Then, if the cursor is at position zero...
        if (getText().length() > 0 && selStart == 0) {
            // ...move it over to position one.
            setSelection(1, selEnd);
        }
    }
}

This will force the cursor to always go after the currency symbol even if the user attempts to move it before it. The check getText().length() > 0 is to ensure that the EditText contains at least one character, otherwise attempting to move the cursor will result in an Exception.

As for #2, there are a couple ways to go at it. You can attempt to use some instance variables inside your TextWatcher to keep track of when the text needs to be formatted, but that won't prevent the unnecessary method calls from actually happening, and it adds some unneeded complexity. I think it would be easier to simply use an InputFilter, which you can specify in your extended EditText's constructor.

public class MyEditText extends EditText {

    public MyEditText(Context context) {
        super(context);

        // Set the EditText's input filter.
        setFilters(new InputFilter[] { new InputFilter {
            @Override
            public CharSequence filter(CharSequence source, int start, int end,
                                        Spanned dest, int dstart, int dend) {
                // If the currency symbol is about to be replaced...
                if (dstart == 0)
                    // Add the currency symbol to the front of the source.
                    return currencySymbol + source;
                // else
                    // Return null to indicate that the change is okay.
                    return null;
            } 
        }});
    }

    // ...
}

In the filter method, the dest parameter represents the EditText's text, and the dstart and dend parameters represent the start and end positions of the portion of the text that is about to be replaced. Since the currency symbol should always be the first character, we know it is about to be replaced if dstart is zero, in which case we simply return the source (which represents the replacement text) with the currency symbol placed in front. Otherwise, we indicate that the change is okay by returning null.

I tested it, and it seems to work for what you need.

On a side note, although I understand that you're not "allowed" to use a TextView, I think it's worth reiterating that using one would provide a much better solution to this problem. One particularly useful solution being to have a hidden EditText contain the raw input from the user, and having the TextView on top of the EditText. You would use a TextWatcher to update the TextView with the properly formatted input from the EditText.

Question:

what I'm trying to do is to make Editext except only word or number that not start with zero so I did this

mPatentNameET.setFilters(new InputFilter[] {
                new InputFilter() {
                    public CharSequence filter(CharSequence src, int start,
                                               int end, Spanned dst, int dstart, int dend) {
                        if(src.equals("")){ // for backspace
                            return src;
                        }
                        if(src.toString().matches("[a-zA-Z ]+")  ||
                                src.toString().matches("^[123456789][0-9]$")){
                            return src;
                        }
                        return "";
                    }
                }
        });

but didn't work well, I want from EditText to accept for example "Test" or "546" , sorry for my bad English


Answer:

I solve it like this :)

mPatentNameET.setFilters(new InputFilter[] {
                new InputFilter() {
                    public CharSequence filter(CharSequence src, int start,
                                               int end, Spanned dst, int dstart, int dend) {
                        if(src.equals("")){ // for backspace
                            return src;
                        }
                        if((mPatentNameET.getText().toString() + src).matches("[a-zA-Z ]+")  ||
                                (mPatentNameET.getText().toString() + src).matches("^[123456789][0-9]*$")){
                            return src;
                        }
                        return "";
                    }
                }
        });