Edit text for OTP with Each letter in separate positions

后端 未结 19 872
别跟我提以往
别跟我提以往 2020-12-13 00:25

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

相关标签:
19条回答
  • 2020-12-13 00:41

    Use 4 different EditText.Use the below code to change the focus after subsequent entry.

    private EditText editText1;
    private EditText editText2;
    private EditText editText3;
    private EditText editText4;
    
        editText1.addTextChangedListener(new TextWatcher() {
    
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (editText1.getText().toString().length() == 1)     //size as per your requirement
                    {
                        editText2.requestFocus();
                    }
                }
    
                public void beforeTextChanged(CharSequence s, int start,
                                              int count, int after) {
                }
    
                public void afterTextChanged(Editable s) {
                }
    
            });
    
        editText2.addTextChangedListener(new TextWatcher() {
    
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (editText2.getText().toString().length() == 1)     //size as per your requirement
                    {
                        editText3.requestFocus();
                    }
                }
    
                public void beforeTextChanged(CharSequence s, int start,
                                              int count, int after) {
                }
    
                public void afterTextChanged(Editable s) {
                }
    
            });
    

    and so on...

    Concatenate the text from all the EditText.

    0 讨论(0)
  • 2020-12-13 00:43
    public class GenericTextWatcher implements TextWatcher {
        private EditText etPrev;
        private EditText etNext;
    
        public GenericTextWatcher(EditText etNext, EditText etPrev) {
            this.etPrev = etPrev;
            this.etNext = etNext;
        }
    
        @Override
        public void afterTextChanged(Editable editable) {
            String text = editable.toString();
            if (text.length() == 1)
                etNext.requestFocus();
            else if (text.length() == 0)
                etPrev.requestFocus();
        }
    
        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        }
    
        @Override
        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        }
    }
    

    Next, we add the addTextChangedListener on each edittext.

    e1.addTextChangedListener(new GenericTextWatcher(e2, e1))
    e2.addTextChangedListener(new GenericTextWatcher(e3, e1))
    e3.addTextChangedListener(new GenericTextWatcher(e4, e2))
    e4.addTextChangedListener(new GenericTextWatcher(e5, e3))
    e5.addTextChangedListener(new GenericTextWatcher(e6, e4))
    e6.addTextChangedListener(new GenericTextWatcher(e6, e5))
    
    0 讨论(0)
  • 2020-12-13 00:44

    i made a generic TextWatcher for 6 digit OTP:

    public class GenericTextWatcher implements TextWatcher {
            private View view;
    
            GenericTextWatcher(View view) {
                this.view = view;
            }
    
            @Override
            public void afterTextChanged(Editable s) {
                boolean allOtherFilled = false;
                EditText nextEdit = null;
                EditText previousEdit = null;
                switch (view.getId()) {
                    case R.id.otp_et1:
                        allOtherFilled = otpEdit2.getText().length() == 1
                                && otpEdit3.getText().length() == 1
                                && otpEdit4.getText().length() == 1
                                && otpEdit5.getText().length() == 1
                                && otpEdit6.getText().length() == 1;
                        nextEdit = otpEdit2;
                        break;
                    case R.id.otp_et2:
                        allOtherFilled = otpEdit1.getText().length() == 1
                                && otpEdit3.getText().length() == 1
                                && otpEdit4.getText().length() == 1
                                && otpEdit5.getText().length() == 1
                                && otpEdit6.getText().length() == 1;
                        nextEdit = otpEdit3;
                        previousEdit = otpEdit1;
                        break;
                    case R.id.otp_et3:
                        allOtherFilled = otpEdit1.getText().length() == 1
                                && otpEdit2.getText().length() == 1
                                && otpEdit4.getText().length() == 1
                                && otpEdit5.getText().length() == 1
                                && otpEdit6.getText().length() == 1;
                        nextEdit = otpEdit4;
                        previousEdit = otpEdit2;
                        break;
                    case R.id.otp_et4:
                        allOtherFilled = otpEdit1.getText().length() == 1
                                && otpEdit2.getText().length() == 1
                                && otpEdit3.getText().length() == 1
                                && otpEdit5.getText().length() == 1
                                && otpEdit6.getText().length() == 1;
                        nextEdit = otpEdit5;
                        previousEdit = otpEdit3;
                        break;
                    case R.id.otp_et5:
                        allOtherFilled = otpEdit1.getText().length() == 1
                                && otpEdit2.getText().length() == 1
                                && otpEdit3.getText().length() == 1
                                && otpEdit4.getText().length() == 1
                                && otpEdit6.getText().length() == 1;
                        nextEdit = otpEdit6;
                        previousEdit = otpEdit4;
                        break;
                    case R.id.otp_et6:
                        allOtherFilled = otpEdit1.getText().length() == 1
                                && otpEdit2.getText().length() == 1
                                && otpEdit3.getText().length() == 1
                                && otpEdit4.getText().length() == 1
                                && otpEdit5.getText().length() == 1;
                        previousEdit = otpEdit5;
                        break;
                }
    
                if (s.length() == 1) {
                    if (allOtherFilled) {
                        //if next 2 edit texts are filled , enable the pay button
                        enableDisableButton(continueButton, true);
                        KeyboardUtils.hideKeyboard(LoginActivity.this, (EditText) view);
                    }
                } else if (s.length() > 1) {
                    if (allOtherFilled) {
                        //if all next edit texts are filled , enable the pay button
                        enableDisableButton(continueButton, true);
                        KeyboardUtils.hideKeyboard(LoginActivity.this, (EditText) view);
    
                    } else if (nextEdit != null) {
                        if (nextEdit.getText().length() == 0) {
                            //if next edit is not filled, move to next edit and set the second digit
                            moveToNextEdit(nextEdit, (EditText) view);
                        } else {
                            //if any other edit is not filled, stay in current edit
                            enableDisableButton(continueButton, false);
                            stayOnCurrentEdit((EditText) view);
                        }
                    }
                } else if (s.length() < 1) {
                    if (null != previousEdit)
                        moveToPreviousEdit(previousEdit);
                    enableDisableButton(continueButton, false);
                }
            }
    
            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            }
    
            @Override
            public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            }
    
            private void stayOnCurrentEdit(EditText editText) {
                editText.setText(editText.getText().toString().substring(0, 1));
                editText.setSelection(editText.getText().length());
            }
    
            private void moveToPreviousEdit(EditText editText) {
                editText.setSelection(editText.getText().length());
                editText.requestFocus();
            }
    
            private void moveToNextEdit(EditText editText2, EditText editText1) {
                editText2.setText(editText1.getText().toString().substring(1, 2));
                editText2.requestFocus();
                editText2.setSelection(editText2.getText().length());
                editText1.setText(editText1.getText().toString().substring(0, 1));
            }
        }
    

    You can add this textWatcher to all your edit texts like this :

    this.otpEdit1.addTextChangedListener(new GenericTextWatcher(otpEdit1));
    
    0 讨论(0)
  • 2020-12-13 00:46

    For the question asked by @SachinMandhare on https://stackoverflow.com/a/57337907/8765580

    Just modify the code to

    String pattern = "";
    for (int j = 0; j < getText().toString().length(); j++) {
        pattern += "*"; //Any Character that you want to display 
    }
    for (int i = 0; i < mNumChars; i++) {
        canvas.drawLine(startX, bottom, startX + mCharSize, bottom, mLinesPaint);
        if (getText().length() > i) {
             float middle = startX + mCharSize / 2;
             canvas.drawText(pattern, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint());
        }
        if (mSpace < 0) {
            startX += mCharSize * 2;
        } else {
            startX += mCharSize + mSpace;
        }
    }
    
    0 讨论(0)
  • 2020-12-13 00:47

    You can try this if you want to add some extra logic for delete the OTP, i create it based on the answer from A.R. make sure you set maxlength = 2 for all edittext

    public class GenericTextWatcher implements TextWatcher
    {
        private View view;
        private GenericTextWatcher(View view)
        {
            this.view = view;
        }
        @Override
        public void afterTextChanged(Editable editable) {
            // TODO Auto-generated method stub
            String text = editable.toString();
            switch (view.getId()) {
    
                case R.id.etOTP1:
                    if (text.length() > 1) {
                        etOTP1.setText(String.valueOf(text.charAt(0)));
                        etOTP2.setText(String.valueOf(text.charAt(1)));
                        etOTP2.requestFocus();
                        etOTP2.setSelection(etOTP2.getText().length());
                    }
                    break;
                case R.id.etOTP2:
                    if (text.length() > 1){
                        etOTP2.setText(String.valueOf(text.charAt(0)));
                        etOTP3.setText(String.valueOf(text.charAt(1)));
                        etOTP3.requestFocus();
                        etOTP3.setSelection(etOTP3.getText().length());
                    }
                    if (text.length() == 0){
                        etOTP1.requestFocus();
                        etOTP1.setSelection(etOTP1.getText().length());
                    }
                    break;
                case R.id.etOTP3:
                    if (text.length() > 1){
                        etOTP3.setText(String.valueOf(text.charAt(0)));
                        etOTP4.setText(String.valueOf(text.charAt(1)));
                        etOTP4.requestFocus();
                        etOTP4.setSelection(etOTP4.getText().length());
                    }
                    if (text.length() == 0){
                        etOTP2.requestFocus();
                        etOTP2.setSelection(etOTP2.getText().length());
                    }
                    break;
                case R.id.etOTP4:
                    if (text.length() == 0){
                        etOTP3.requestFocus();
                        etOTP3.setSelection(etOTP3.getText().length());
                    }
                    break;
            }
        }
        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        }
    
        @Override
        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        }
    }
    
    0 讨论(0)
  • 2020-12-13 00:51

    After all of these answers, I didn't find what I wanted as considering the UI/UX, the deletion of element was flawed in such a way that to go back to previous EditText, current EditText should not be empty.

    Here's the solution I've implemented in Kotlin which works for Deletion by the Delete Key, pressed on the keyboard. Also, the delete function is implemented as such that when the current EditText is empty and Delete key is pressed, it switches back to previous EditText and delete its element also.

    1. Call the functions as such:

      //GenericTextWatcher here works only for moving to next EditText when a number is entered
      //first parameter is the current EditText and second parameter is next EditText
      editText1.addTextChangedListener(GenericTextWatcher(editText1, editText2))
      editText2.addTextChangedListener(GenericTextWatcher(editText2, editText3))
      editText3.addTextChangedListener(GenericTextWatcher(editText3, editText4))
      editText4.addTextChangedListener(GenericTextWatcher(editText4, null))
      
      //GenericKeyEvent here works for deleting the element and to switch back to previous EditText
      //first parameter is the current EditText and second parameter is previous EditText
      editText1.setOnKeyListener(GenericKeyEvent(editText1, null))
      editText2.setOnKeyListener(GenericKeyEvent(editText2, editText1))
      editText3.setOnKeyListener(GenericKeyEvent(editText3, editText2))
      editText4.setOnKeyListener(GenericKeyEvent(editText4,editText3))
      
    2. Now, paste these two classes in your current class

      class GenericKeyEvent internal constructor(private val currentView: EditText, private val previousView: EditText?) : View.OnKeyListener{
          override fun onKey(p0: View?, keyCode: Int, event: KeyEvent?): Boolean {
              if(event!!.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DEL && currentView.id != R.id.editText1 && currentView.text.isEmpty()) {
                  //If current is empty then previous EditText's number will also be deleted
                  previousView!!.text = null 
                  previousView.requestFocus()
                  return true
              }
              return false
          }
      
      
      }
      
      class GenericTextWatcher internal constructor(private val currentView: View, private val nextView: View?) : TextWatcher {
          override fun afterTextChanged(editable: Editable) { // TODO Auto-generated method stub
              val text = editable.toString()
              when (currentView.id) {
                  R.id.editText1 -> if (text.length == 1) nextView!!.requestFocus()
                  R.id.editText2 -> if (text.length == 1) nextView!!.requestFocus()
                  R.id.editText3 -> if (text.length == 1) nextView!!.requestFocus()
                  //You can use EditText4 same as above to hide the keyboard
              }
          }
      
          override fun beforeTextChanged(
              arg0: CharSequence,
              arg1: Int,
              arg2: Int,
              arg3: Int
          ) { // TODO Auto-generated method stub
          }
      
          override fun onTextChanged(
              arg0: CharSequence,
              arg1: Int,
              arg2: Int,
              arg3: Int
          ) { // TODO Auto-generated method stub
          }
      
      }
      

    Further, to disable the visible cursor, you can either use android:cursorVisible="false" in your EditText tag in the Layout or can use the java function setCursorVisible(false).

    Edit: I'm using stock widget EditTexts so if you want to display a box around them, just create a drawable layout and set it as background of EditTexts and give them a padding of 5dp. This will create a box and will make it look cooler.

    0 讨论(0)
提交回复
热议问题