I\'m working on a application which asks for OTP when user want to reset his password for which I need a text like the one in attached Image... What I thought to proceed wi
I implemented the following code based on other answers.
I wanted this code to be very simple, optimized and understandable for changes.
Don't use android:maxLength="1" in your xml.
//package your package
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
public class PinActivity extends AppCompatActivity {
private EditText editText1, editText2, editText3, editText4;
private EditText[] editTexts;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pin);
editText1 = (EditText) findViewById(R.id.otpEdit1);
editText2 = (EditText) findViewById(R.id.otpEdit2);
editText3 = (EditText) findViewById(R.id.otpEdit3);
editText4 = (EditText) findViewById(R.id.otpEdit4);
editTexts = new EditText[]{editText1, editText2, editText3, editText4};
editText1.addTextChangedListener(new PinTextWatcher(0));
editText2.addTextChangedListener(new PinTextWatcher(1));
editText3.addTextChangedListener(new PinTextWatcher(2));
editText4.addTextChangedListener(new PinTextWatcher(3));
editText1.setOnKeyListener(new PinOnKeyListener(0));
editText2.setOnKeyListener(new PinOnKeyListener(1));
editText3.setOnKeyListener(new PinOnKeyListener(2));
editText4.setOnKeyListener(new PinOnKeyListener(3));
}
public class PinTextWatcher implements TextWatcher {
private int currentIndex;
private boolean isFirst = false, isLast = false;
private String newTypedString = "";
PinTextWatcher(int currentIndex) {
this.currentIndex = currentIndex;
if (currentIndex == 0)
this.isFirst = true;
else if (currentIndex == editTexts.length - 1)
this.isLast = true;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
newTypedString = s.subSequence(start, start + count).toString().trim();
}
@Override
public void afterTextChanged(Editable s) {
String text = newTypedString;
/* Detect paste event and set first char */
if (text.length() > 1)
text = String.valueOf(text.charAt(0)); // TODO: We can fill out other EditTexts
editTexts[currentIndex].removeTextChangedListener(this);
editTexts[currentIndex].setText(text);
editTexts[currentIndex].setSelection(text.length());
editTexts[currentIndex].addTextChangedListener(this);
if (text.length() == 1)
moveToNext();
else if (text.length() == 0)
moveToPrevious();
}
private void moveToNext() {
if (!isLast)
editTexts[currentIndex + 1].requestFocus();
if (isAllEditTextsFilled() && isLast) { // isLast is optional
editTexts[currentIndex].clearFocus();
hideKeyboard();
}
}
private void moveToPrevious() {
if (!isFirst)
editTexts[currentIndex - 1].requestFocus();
}
private boolean isAllEditTextsFilled() {
for (EditText editText : editTexts)
if (editText.getText().toString().trim().length() == 0)
return false;
return true;
}
private void hideKeyboard() {
if (getCurrentFocus() != null) {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
}
}
public class PinOnKeyListener implements View.OnKeyListener {
private int currentIndex;
PinOnKeyListener(int currentIndex) {
this.currentIndex = currentIndex;
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
if (editTexts[currentIndex].getText().toString().isEmpty() && currentIndex != 0)
editTexts[currentIndex - 1].requestFocus();
}
return false;
}
}
}