3

I have read this question How to disable Button if EditText is empty ?

But there it is only 1 EditText field. What is an elegant solution to use a TextWatcher to enable or disable a Button if both of two EditText fields are either empty or contain text?

This is my approach and it works, but it makes no use of any of the arguments passed in onTextChanged. What do you think?

public class MainActivity extends AppCompatActivity implements TextWatcher {
private EditText editTextUsername;
private EditText editTextPassword;
private Button buttonConfirm;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    editTextUsername = findViewById(R.id.edit_text);
    editTextPassword = findViewById(R.id.edit_password);
    buttonConfirm = findViewById(R.id.button_confirm);


    editTextUsername.addTextChangedListener(this);
    editTextPassword.addTextChangedListener(this);
}

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

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    String usernameInput = editTextUsername.getText().toString().trim();
    String passwordInput = editTextPassword.getText().toString().trim();

    buttonConfirm.setEnabled(!usernameInput.isEmpty() && !passwordInput.isEmpty());
}

@Override
public void afterTextChanged(Editable s) {

}
}
Florian Walther
  • 6,237
  • 5
  • 46
  • 104

4 Answers4

2

You can set listeners to both EditText as in

editTextUsername.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) {
              button.setEnabled(editTextUsername.getText().toString().trim().length() > 0 
                  && editTextPassword .getText().toString().trim().length() > 0 ); 
            }

            @Override
            public void afterTextChanged(Editable s) {

             }
        });

    editTextPassword.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) {
              button.setEnabled(editTextUsername.getText().toString().trim().length() > 0 
                  && editTextPassword .getText().toString().trim().length() > 0 ); 
            }

            @Override
            public void afterTextChanged(Editable s) {

             }
        });
Rajan Kali
  • 12,627
  • 3
  • 25
  • 37
  • Ok thank you, this looks pretty similar to the solution I just edited in. I just passed the MainActivity as the listener instead. – Florian Walther Apr 06 '18 at 08:51
2

Maybe you can create a wrapper for your editTexts like this.

public class MyEditText extends AppCompatEditText implements TextWatcher {

    public interface LoginTextWatcher {
        void onTextChanged(String... texts);
    }

    private static List<MyEditText> myEditTextList = new ArrayList<>();
    private static LoginTextWatcher loginTextWatcherListener;

    public MyEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyEditText(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyEditText(Context context) {
        this(context, null, 0);
    }

    public static void setLoginTextWatcherListener(LoginTextWatcher listener) {
       loginTextWatcherListener = listener;
    }

    public void addLoginTextWatcher() {
        super.addTextChangedListener(this);
        myEditTextList.add(this);
    }

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        if (loginTextWatcherListener != null) {
            String[] textArray = new String[myEditTextList.size()];
            for (int index = 0; index < myEditTextList.size(); index++) {
                textArray[index] = myEditTextList.get(index).getText().toString();
            }
            loginTextWatcherListener.onTextChanged(textArray);
        }
    }

    @Override
    public void afterTextChanged(Editable editable) {

    }

Then you use it like this,

public class MainActivity extends AppCompatActivity implements LoginTextWatcher {

private MyEditText editTextUsername;
private MyEditText editTextPassword;
private Button buttonConfirm;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    editTextUsername = findViewById(R.id.edit_text);
    editTextPassword = findViewById(R.id.edit_password);
    buttonConfirm = findViewById(R.id.button_confirm);

    MyEditText.setLoginTextWatcherListener(this);
    editTextUsername.addLoginTextWatcher();
    editTextPassword.addLoginTextWatcher();
}

@Override
public void onTextChanged(String... texts) {
   //do your work
}

}

What I did it here is not a big deal. You have a wrapper, manages callbacks there and pass to activity what you want and as you want. I believe your activity looks more elegant in this way. You can pass editTexts if you don't wanna loop after every text change. You know, you can change things as you wish. It is also nice to add methods into MyEditText class to remove those static references and call them at some point. Maybe when the activity is destroying.

anzaidemirzoi
  • 386
  • 4
  • 13
1

Use textwatcher for both edittext

Add one more condition for checking anotheredittext.getText().toString().trim().isEmpty()

And use this code to enable button in both textwatcher,

 buttonConfirm.setEnabled(!(s.toString().trim().isEmpty() || anotheredittext.getText().toString().trim().isEmpty()));
Jyoti JK
  • 2,141
  • 1
  • 17
  • 40
0

Kotlin version of @anzaidemirzoi's answer (also, for a TextInputEditText as that is what I'm using):

import android.content.Context
import android.support.design.widget.TextInputEditText
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet

class TextWatcherInputEditText @JvmOverloads
    constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    TextInputEditText(context, attrs, defStyleAttr),
    TextWatcher {

    interface IntegratedTextWatcher {
        fun onTextChanged(texts: String)
    }

    init {
        super.addTextChangedListener(this)
    }
    private var integratedTextWatcherListener: IntegratedTextWatcher? = null

    fun setLoginTextWatcherListener(listener: IntegratedTextWatcher) {
        integratedTextWatcherListener = listener
    }

    override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {

    }

    override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
        if (integratedTextWatcherListener != null) {
            integratedTextWatcherListener!!.onTextChanged(charSequence.toString())
        }
    }

    override fun afterTextChanged(editable: Editable) {

    }
}
ChrisPrime
  • 458
  • 1
  • 6
  • 13