1

I have a bunch of fields: first name, last name, e-mail, password and I need to update the progress bar every time they have valid entries in them. So e.g. if email address and last name are filled the ProgressBar should be 50% full. The user can enter the fields in any order but the ProgressBar should always show what the updated progress level is. I am using addTextChangeListener(Text Watcher).

firstName.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            int length = s.toString().trim().length();
            if (length > 0) {
                registrationProgress.setProgress(registrationProgress.getProgress() + 25);
            } else {
                registrationProgress.setProgress(registrationProgress.getProgress() - 25);
            }

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

When I run the above, I get the ProgressBar to keep on adding 25 with every text entry instead of when the entire field is populated and the user as tapped out of that field. What am I doing wrong and what should I do?

Juanje
  • 1,235
  • 2
  • 11
  • 28
BVB09
  • 805
  • 9
  • 19

3 Answers3

1

When I run the above, I get the progress bar to keep on adding 25 with every text entry [...] What am I doing wrong?

Differences between TextWatcher's onTextChanged, beforeTextChanged and afterTextChanged will help you to understand why your app is behaving that way.

what should I do?

You can override afterTextChanged() instead of onTextChanged() because you're not interested in how often the user typed a letter (or hit the backspace key). In afterTextChanged(), you evaluate the length of the String which has been entered in the EditText so far.

In order to keep track of the progress, I'd like to introduce a

private SparseBooleanArray isTextComplete = new SparseBooleanArray();

as well as a method

private void checkProgress(){
    int progress = 0;
    for(int i = 0; i <  isTextComplete.size(); i++){
        if(isTextComplete.valueAt(i)){
            progress++;
        }
    }
    registrationProgress.setProgress(progress * 25);
}

In afterTextChanged(), you can update the SparseBooleanArray and call checkProgress():

@Override
public void afterTextChanged(Editable s) {
    int len = etMail.getText().toString().length();
    if(len > 0){
        isTextComplete.put(etMail.getId(), true);
    }
    else{
        isTextComplete.put(etMail.getId(), false);
    }
    checkProgress();
}
Bö macht Blau
  • 12,820
  • 5
  • 40
  • 61
0

When I run the above, I get the progress bar to keep on adding 25 with every text

This is because you're using the following code (please read the comment):

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    int length = s.toString().trim().length();

    // if string not empty, keep adding the progress with 25
    if (length > 0) {
        registrationProgress.setProgress(registrationProgress.getProgress() + 25);
    } 
    // subtract 25 each time string empty.
    else {
        registrationProgress.setProgress(registrationProgress.getProgress() - 25);
    }

}

you can see that you're always adding 25 if there is a non empty string or subtracting 25 if no non empty string found.

To solve the problem, you need to keep tracking for each text change in first name, last name, e-mail, password. You can use HashMap combined with Enum. Something like this:

public YourActivity extends AppCompatActivity {

   ...

   // this is the list of entry
   private enum Entry {
     FIRST_NAME, LAST_NAME, EMAIL, PASSWORD
   }

   // keep tracking the entry where Boolean is the value if entry already inserted
   private HashMap<Entry, Boolean> mMapEntries = new HashMap<>();

   private void checkAndValidateEntries() {
     // initialize the entry as not inserted yet
     mMapEntries.put(FIRST_NAME, false);
     mMapEntries.put(LAST_NAME, false);
     mMapEntries.put(EMAIL, false);
     mMapEntries.put(PASSWORD, false);


     // then handle the entry view
     // here the example only for firstname
     firstName.addTextChangedListener(new TextWatcher() {
        ...

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            int length = s.toString().trim().length();
            if (length > 0) {
               boolean isInserted = mMapEntries.get(FIRST_NAME);
               // do changes if entry not yet inserted before.
               if(isInserted == false) {
                  // progress percentage per entry
                  int percentage = 100 / mMapEntries.size();

                  // add the progress
                  int progress = registrationProgress.getProgress() + percentage;
                  registrationProgress.setProgress(progress);

                  // we now have inserted the value, so mark it.
                  mMapEntries.put(FIRST_NAME, true);
               }
            } else {
               boolean isInserted = mMapEntries.get(FIRST_NAME);
               // Do changes if entry already inserted before.
               if(isInserted == true) {
                  int percentage = 100 / mMapEntries.size();

                  // subtract the progress.
                  int progress = registrationProgress.getProgress() - percentage;
                 registrationProgress.setProgress(progress);

                 // entry is removed, mark as not inserted yet
                 mMapEntries.put(FIRST_NAME, false);
               }
            }

        }

        ...
     });


     // handle the last name, e-mail, password
     ...
   }

}

The above code will only increase the progress value if an entry progress isn't added to the progress before and vice versa.

ישו אוהב אותך
  • 28,609
  • 11
  • 78
  • 96
0

The problem is that you are adding 25 each time that the field text is changing. For example, if you write "Hello", you have five letters so onTextChanged will be triggered 5 times.

A possible workarrond is to create flags for each field, just a boolean to indicate if the field is filled or not. Then you check how many flags are set to "filled" and set the ProgressBar accordingly.

Hope it helps.

Juanje
  • 1,235
  • 2
  • 11
  • 28