android on Text Change Listener

2019-01-01 12:58发布

I have a situation, where there are two fields. field1 and field2. All I want to do is empty field2 when field1 is changed and vice versa. So at the end only one field has content on it.

field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);

field1.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) {
      field2.setText("");
   }
  });

field2.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) {
     field1.setText("");
   }
  });

It works fine if I attach addTextChangedListener to field1 only, but when I do it for both fields the app crashes. Obviously because they try to change each other indefinitely. Once field1 changes it clears field2 at this moment field2 is changed so it will clear field1 and so on...

Can someone suggest any solution?

7条回答
ら面具成の殇う
2楼-- · 2019-01-01 13:22

You can add a check to only clear when the text in the field is not empty (i.e when the length is different than 0).

field1.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

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

   @Override    
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
        field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

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

   @Override
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
         field1.setText("");
   }
  });

Documentation for TextWatcher here.

Also please respect naming conventions.

查看更多
不流泪的眼
3楼-- · 2019-01-01 13:24

I know this is old but someone might come across this again someday.

I had a similar problem where I would call setText on a EditText and onTextChanged would be called when I didn't want it to. My first solution was to write some code after calling setText() to undo the damage done by the listener. But that wasn't very elegant. After doing some research and testing I discovered that using getText().clear() clears the text in much the same way as setText(""), but since it isn't setting the text the listener isn't called, so that solved my problem. I switched all my setText("") calls to getText().clear() and I didn't need the bandages anymore, so maybe that will solve your problem too.

Try this:

Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);

Field1.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) {
      Field2.getText().clear();
   }
  });

Field2.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) {
     Field1.getText().clear();
   }
  });
查看更多
怪性笑人.
4楼-- · 2019-01-01 13:26

A bit late of a answer, but here is a reusable solution:

/**
 * An extension of TextWatcher which stops further callbacks being called as 
 * a result of a change happening within the callbacks themselves.
 */
public abstract class EditableTextWatcher implements TextWatcher {

    private boolean editing;

    @Override
    public final void beforeTextChanged(CharSequence s, int start, 
                                                    int count, int after) {
        if (editing)
            return;

        editing = true;
        try {
            beforeTextChange(s, start, count, after);
        } finally {
            editing = false;
        }
    }

    protected abstract void beforeTextChange(CharSequence s, int start, 
                                                     int count, int after);

    @Override
    public final void onTextChanged(CharSequence s, int start, 
                                                int before, int count) {
        if (editing)
            return;

        editing = true;
        try {
            onTextChange(s, start, before, count);
        } finally {
            editing = false;
        }
    }

    protected abstract void onTextChange(CharSequence s, int start, 
                                            int before, int count);

    @Override
    public final void afterTextChanged(Editable s) {
        if (editing)
            return;

        editing = true;
        try {
            afterTextChange(s);
        } finally {
            editing = false;
        }
    }

    public boolean isEditing() {
        return editing;
    }

    protected abstract void afterTextChange(Editable s);
}

So when the above is used, any setText() calls happening within the TextWatcher will not result in the TextWatcher being called again:

/**
 * A setText() call in any of the callbacks below will not result in TextWatcher being 
 * called again.
 */
public class MyTextWatcher extends EditableTextWatcher {

    @Override
    protected void beforeTextChange(CharSequence s, int start, int count, int after) {
    }

    @Override
    protected void onTextChange(CharSequence s, int start, int before, int count) {
    }

    @Override
    protected void afterTextChange(Editable s) {
    }
}
查看更多
人间绝色
5楼-- · 2019-01-01 13:29

You can also use the hasFocus() method:

public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     if (Field2.hasfocus()){
         Field1.setText("");
     }
   }

Tested this for a college assignment I was working on to convert temperature scales as the user typed them in. Worked perfectly, and it's way simpler.

查看更多
梦醉为红颜
6楼-- · 2019-01-01 13:31

check String before set another EditText to empty. if Field1 is empty then why need to change again to ( "" )? so you can check the size of Your String with s.lenght() or any other solution

another way that you can check lenght of String is:

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}
查看更多
弹指情弦暗扣
7楼-- · 2019-01-01 13:37

I have also faced the same problem and keep on getting stack full exceptions, and I come with the following solution.

    edt_amnt_sent.addTextChangedListener(new TextWatcher() {    
        @Override
        public void afterTextChanged(Editable s) {

            if (skipOnChange)
                return;

            skipOnChange = true;
            try {
                //method
                }
            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                skipOnChange = false;
            }
        }
    });

    edt_amnt_receive.addTextChangedListener(new TextWatcher() {


        @Override
        public void afterTextChanged(Editable s) {

            if (skipOnChange)
                return;

            skipOnChange = true;
            try 
            {
                //method
            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                skipOnChange = false;
            }
        }
    });

declared initially boolean skipOnChange = false;

查看更多
登录 后发表回答