Edit text for OTP with Each letter in separate positions

后端 未结 19 874
别跟我提以往
别跟我提以往 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:51

    using DataBinding layout:

    public class EnterOTPActivity extends AppCompatActivity {
                private ActivityEnterOtpBinding binding;
                private Context mContext;
                private int currentEditIndex;
    
    
                @Override
                protected void onCreate(@Nullable Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    binding = DataBindingUtil.setContentView(this, R.layout.activity_enter_otp);
                    mContext = this;
    
                    binding.et1.addTextChangedListener(new MyTextChangeWatcher(1));
                    binding.et2.addTextChangedListener(new MyTextChangeWatcher(2));
                    binding.et3.addTextChangedListener(new MyTextChangeWatcher(3));
                    binding.et4.addTextChangedListener(new MyTextChangeWatcher(4));
                    binding.et5.addTextChangedListener(new MyTextChangeWatcher(5));
                    binding.et6.addTextChangedListener(new MyTextChangeWatcher(6));
    
                    binding.et1.setOnKeyListener(keyListener);
                    binding.et2.setOnKeyListener(keyListener);
                    binding.et3.setOnKeyListener(keyListener);
                    binding.et4.setOnKeyListener(keyListener);
                    binding.et5.setOnKeyListener(keyListener);
                    binding.et6.setOnKeyListener(keyListener);
    
    
                }
    
                private View.OnKeyListener keyListener = new View.OnKeyListener() {
    
                    @Override
                    public boolean onKey(View v, int keyCode, KeyEvent event) {
    
                        if ((((EditText) v).getText().toString() == null || ((EditText) v)
                                .getText().toString().isEmpty())
                                && keyCode == KeyEvent.KEYCODE_DEL
                                && event.getAction() == KeyEvent.ACTION_DOWN) {
    
                            if (currentEditIndex == 6)
                                currentEditIndex = 5;
                            if (currentEditIndex > 0) {
                                EditText editText = getEditTextFromIndex(currentEditIndex);
                               editText.setText("");
                                editText.requestFocusFromTouch();
                                currentEditIndex--;
                            }
                        }
    
                        return false;
                    }
                };
    
                class MyTextChangeWatcher implements TextWatcher {
                    private int index;
    
                    public MyTextChangeWatcher(int index) {
                        super();
                        this.index = index;
                    }
    
                    @Override
                    public void afterTextChanged(Editable s) {
                        if (s != null && s.length() == 1) {
                            if (index < 7) {
    
                                if (index < 6) {
                                    EditText editText = getEditTextFromIndex(index);
                                    editText.clearFocus();
                                    getEditTextFromIndex(index + 1).requestFocusFromTouch();
                                }
                                currentEditIndex = index;
                            } else {
    
                            }
                        } else {
                        }
                    }
    
                    @Override
                    public void beforeTextChanged(CharSequence s, int start, int count,
                                                  int after) {
                    }
    
                    @Override
                    public void onTextChanged(CharSequence s, int start, int before,
                                              int count) {
                    }
                }
    
                private EditText getEditTextFromIndex(int index) {
                    switch (index) {
                        case 1:
                            return binding.et1;
                        case 2:
                            return binding.et2;
                        case 3:
                            return binding.et3;
                        case 4:
                            return binding.et4;
                        case 5:
                            return binding.et5;
                        case 6:
                            return binding.et6;
    
                        default:
                            break;
                    }
                    return null;
                }
            }
    
    0 讨论(0)
  • 2020-12-13 00:54

    OtpEditText.java (Custom EditText):

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.text.Editable;
    import android.util.AttributeSet;
    import android.view.ActionMode;
    import android.view.View;
    import androidx.appcompat.widget.AppCompatEditText;
    
    public class OtpEditText extends AppCompatEditText {
        private float mSpace = 24; //24 dp by default, space between the lines
        private float mNumChars = 4;
        private float mLineSpacing = 8; //8dp by default, height of the text from our lines
        private int mMaxLength = 4;
        private float mLineStroke = 2;
        private Paint mLinesPaint;
        private OnClickListener mClickListener;
    
        public OtpEditText(Context context) {
            super(context);
        }
    
        public OtpEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs);
        }
    
        public OtpEditText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs);
        }
    
        private void init(Context context, AttributeSet attrs) {
            float multi = context.getResources().getDisplayMetrics().density;
            mLineStroke = multi * mLineStroke;
            mLinesPaint = new Paint(getPaint());
            mLinesPaint.setStrokeWidth(mLineStroke);
            mLinesPaint.setColor(getResources().getColor(R.color.colorPrimaryDark));
            setBackgroundResource(0);
            mSpace = multi * mSpace; //convert to pixels for our density
            mLineSpacing = multi * mLineSpacing; //convert to pixels for our density
            mNumChars = mMaxLength;
    
            super.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // When tapped, move cursor to end of text.
                    setSelection(getText().length());
                    if (mClickListener != null) {
                        mClickListener.onClick(v);
                    }
                }
            });
        }
    
        @Override
        public void setOnClickListener(OnClickListener l) {
            mClickListener = l;
        }
    
        @Override
        public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
            throw new RuntimeException("setCustomSelectionActionModeCallback() not supported.");
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            int availableWidth = getWidth() - getPaddingRight() - getPaddingLeft();
            float mCharSize;
            if (mSpace < 0) {
                mCharSize = (availableWidth / (mNumChars * 2 - 1));
            } else {
                mCharSize = (availableWidth - (mSpace * (mNumChars - 1))) / mNumChars;
            }
    
            int startX = getPaddingLeft();
            int bottom = getHeight() - getPaddingBottom();
    
            //Text Width
            Editable text = getText();
            int textLength = text.length();
            float[] textWidths = new float[textLength];
            getPaint().getTextWidths(getText(), 0, textLength, textWidths);
    
            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(text, i, i + 1, middle - textWidths[0] / 2, bottom - mLineSpacing, getPaint());
                }
                if (mSpace < 0) {
                    startX += mCharSize * 2;
                } else {
                    startX += mCharSize + mSpace;
                }
            }
        }
    }
    

    Use this customised EditText in your XML like below:

    <OtpEditText
        android:id="@+id/et_otp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:cursorVisible="false"
        android:digits="1234567890"
        android:inputType="number"
        android:maxLength="4"
        android:textIsSelectable="false"
        android:textSize="20sp"/>
    

    Reference:
    Article: https://medium.com/@ali.muzaffar/building-a-pinentryedittext-in-android-5f2eddcae5d3
    Sample Code: https://gist.github.com/alphamu/0d3055e0233c5749b8d6

    0 讨论(0)
  • 2020-12-13 00:54

    I created a simple library for this purpose. Check it out. https://github.com/hexdecimal16/EditTextPin
    Usage

    1. Layout XML:
    <com.dhairytripathi.library.EditTextPin
         android:id="@+id/editTextPin"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
    
    1. JAVA file:
    EditTextPin editTextPin = findViewById(R.id.editTextPin);
    String pin = editTextPin.getPin(); //To get the current entered pin
    
    1. Additional styling:
    app:underlineColor="" <!-- To change underline color-->
    
    0 讨论(0)
  • 2020-12-13 00:56

    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;
            }
    
        }
    
    }
    
    0 讨论(0)
  • 2020-12-13 00:56

    using DataBinding :

    class EnterOTPDialogFragment extends Fragment {
        FragmentEnterOtpdialogBinding binding;
        GenericTextWatcher watcher1;
        GenericTextWatcher watcher2;
        GenericTextWatcher watcher3;
        GenericTextWatcher watcher4;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
    
            binding = DataBindingUtil.inflate(inflater, R.layout.fragment_enter_otpdialog, container, false);
    
            watcher1 = new GenericTextWatcher(binding.optDigit1);
            watcher2 = new GenericTextWatcher(binding.optDigit2);
            watcher3 = new GenericTextWatcher(binding.optDigit3);
            watcher4 = new GenericTextWatcher(binding.optDigit4);
            binding.optDigit1.addTextChangedListener(watcher1);
            binding.optDigit1.setOnKeyListener(watcher1);
            binding.optDigit2.addTextChangedListener(watcher2);
            binding.optDigit2.setOnKeyListener(watcher2);
            binding.optDigit3.addTextChangedListener(watcher3);
            binding.optDigit3.setOnKeyListener(watcher3);
            binding.optDigit4.addTextChangedListener(watcher4);
            binding.optDigit4.setOnKeyListener(watcher4);
            return binding.getRoot();
        }
    
        public class GenericTextWatcher implements TextWatcher, View.OnKeyListener {
            private View view;
            String previousText = "";
    
            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.optDigit1:
                        if (text.length() == 1) {
                            if (previousText.length() > 0) {
                                binding.optDigit1.removeTextChangedListener(watcher1);
                                binding.optDigit1.setText(previousText);
                                binding.optDigit1.addTextChangedListener(watcher1);
    
                                binding.optDigit2.removeTextChangedListener(watcher2);
                                binding.optDigit2.setText(text);
                                binding.optDigit2.addTextChangedListener(watcher2);
                            }
                            binding.optDigit2.requestFocus();
                        }
                        break;
                    case R.id.optDigit2:
                        if (text.length() == 1) {
                            if (previousText.length() > 0) {
                                binding.optDigit2.removeTextChangedListener(watcher2);
                                binding.optDigit2.setText(previousText);
                                binding.optDigit2.addTextChangedListener(watcher2);
    
                                binding.optDigit3.removeTextChangedListener(watcher3);
                                binding.optDigit3.setText(text);
                                binding.optDigit3.addTextChangedListener(watcher3);
    
                            }
                            binding.optDigit3.requestFocus();
    
                        } else if (text.length() == 0)
                            binding.optDigit1.requestFocus();
                        break;
                    case R.id.optDigit3:
                        if (text.length() == 1) {
                            if (previousText.length() > 0) {
                                binding.optDigit3.removeTextChangedListener(watcher3);
                                binding.optDigit3.setText(previousText);
                                binding.optDigit3.addTextChangedListener(watcher3);
    
                                binding.optDigit4.removeTextChangedListener(watcher4);
                                binding.optDigit4.setText(text);
                                binding.optDigit4.addTextChangedListener(watcher4);
                            }
                            binding.optDigit4.requestFocus();
                        } else if (text.length() == 0)
                            binding.optDigit2.requestFocus();
                        break;
                    case R.id.optDigit4:
                        if (text.length() == 0) {
    
                            binding.optDigit3.requestFocus();
                        } else {
                            try {
                                final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                                imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
                                Log.e(TAG, "afterTextChanged: hide keyboard");
                            } catch (Exception e) {
                                Log.e(TAG, "afterTextChanged: " + e.toString());
                            }
                        }
    
    
                        break;
                }
            }
    
            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
                // TODO Auto-generated method stub
                Log.d(TAG, "beforeTextChanged: " + arg0);
                if (arg0.length() > 0) {
                    previousText = arg0.toString();
                }
            }
    
            @Override
            public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
                // TODO Auto-generated method stub
            }
    
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                previousText = "";
                Log.d(TAG, "onKey: keyCode = " + keyCode + ", event = " + event.toString());
                if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KEYCODE_DEL) {
                    switch (view.getId()) {
                        case R.id.optDigit2:
                            if (binding.optDigit2.getText().toString().trim().length() == 0)
                                binding.optDigit1.requestFocus();
                            break;
                        case R.id.optDigit3:
                            if (binding.optDigit3.getText().toString().trim().length() == 0)
                                binding.optDigit2.requestFocus();
                            break;
                        case R.id.optDigit4:
                            if (binding.optDigit4.getText().toString().trim().length() == 0)
                                binding.optDigit3.requestFocus();
                            else if (binding.optDigit4.getText().toString().trim().length() == 1)
                                try {
    
                                    ((BaseActivity) getActivity()).hideSoftKeyboard();
                                } catch (Exception e) {
                                    Log.e(TAG, "afterTextChanged: " + e.toString());
                                }
                            break;
                    }
    
                }
                return false;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-13 00:56

    You can make a custom Editext and add it in your xml file, find below a custom class

    public class CustomEntryEdittext extends LinearLayout { 
    
        public int entryCount = 0; //count of boxes to be created
        private int currentIndex = 0;
        private static int EDITTEXT_MAX_LENGTH = 1; //character size of each editext
        private static int EDITTEXT_WIDTH = 40;
        private static int EDITTEXT_TEXTSIZE = 20; //textsize
        private boolean disableTextWatcher = false, backKeySet = false;
        private TextWatcher txtWatcher;
        private onFinishListerner mListerner;
    
    
        public CustomEntryEdittext(Context context) {
            super(context, null);
        }
    
        public CustomEntryEdittext(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CustomEntryEdittext(Context context, AttributeSet attrs, int defStyle) {
            this(context, attrs, defStyle, 0);
        }
    
        public CustomEntryEdittext(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
            super(context, attrs);
            init(context, attrs);
        }
    
        public void setOnFinishListerner(onFinishListerner listerner) {
            this.mListerner = listerner;
        }
    
        public interface onFinishListerner {
            void onFinish(String enteredText);
        }
    
    
        private void init(Context context, AttributeSet attrs) {
    
            TypedArray a = context.obtainStyledAttributes(attrs,
                    R.styleable.CustomEntryEdittext, 0, 0);
    
    
            entryCount = a.getInteger(R.styleable.CustomEntryEdittext_editextCount, 0);
    
            a.recycle();
    
            setOrientation(LinearLayout.HORIZONTAL);
            setGravity(Gravity.CENTER_VERTICAL);
    
            for (int i = 0; i < entryCount; i++) {
    
                //creates edittext based on the no. of count
                addView(initialiseAndAddChildInLayout(i, context), i);
            }
    
        }
    
        //method focuses of previous editext
        private void getPreviousEditext(int index) {
            if (index > 0) {
                EditText edtxt = (EditText) getChildAt(index - 1);
                disableTextWatcher = true;
    
                 edtxt.setText("");
                edtxt.requestFocus();
                disableTextWatcher = false;
    
            }
        }
    
        //method focuses of previous editext
        private void getPreviousEditextFocus(int index) {
            if (index > 0) {
                EditText edtxt = (EditText) getChildAt(index - 1);
                disableTextWatcher = true;
                edtxt.requestFocus();
                disableTextWatcher = false;
            }
        }
    
    
        //method to focus on next edittext
        private void getNextEditext(int index) {
            if (index < entryCount - 1) {
                EditText edtxt = (EditText) getChildAt(index + 1);
                edtxt.requestFocus();
            }
        }
    
    
        private View initialiseAndAddChildInLayout(int index, Context context) {
            final EditText editext = new EditText(context);
            editext.setMaxWidth(1);
            editext.setTag(index);
            editext.setGravity(Gravity.CENTER);
            editext.setTextSize(EDITTEXT_TEXTSIZE);
            editext.setInputType(EditorInfo.TYPE_CLASS_NUMBER);
            editext.setFilters(new InputFilter[]{new InputFilter.LengthFilter(EDITTEXT_MAX_LENGTH)});
            LayoutParams param = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
            editext.setLayoutParams(param);
            editext.addTextChangedListener(txtWatcher = 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) {
                    currentIndex = Integer.parseInt(editext.getTag().toString());
    
    
                    if (editext.getText().toString().length() == 1 && !disableTextWatcher) {
                        getNextEditext(currentIndex);
                    } else if (editext.getText().toString().length() == 0 && !disableTextWatcher) {// && !isFirstTimeGetFocused && !backKeySet) {
                        getPreviousEditext(currentIndex);
                    }
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
    
    
                }
            });
            editext.setOnKeyListener(new OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (keyCode == KeyEvent.KEYCODE_DEL) {
                        currentIndex = Integer.parseInt(editext.getTag().toString());
                        if (editext.getText().toString().length() == 0 && !disableTextWatcher) {
                            getPreviousEditextFocus(currentIndex);
                        } else {
                            disableTextWatcher = true;
                            editext.setText("");
                            disableTextWatcher = false;
                        }
                        backKeySet = true;
                    }
    
                    return true;
                }
    
    
            });
            editext.setOnEditorActionListener(new TextView.OnEditorActionListener() {
                public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                    if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_DONE)) {
                        if(currentIndex==entryCount-1 && getEnteredText().length()==entryCount)
                        {
                            mListerner.onFinish(getEnteredText());
                        }
                    }
                    return false;
                }
            });
    
            return editext;
        }
    
    
        public String getEnteredText() {
            String strEnteredValue = "";
            for (int i = 0; i < getChildCount(); i++) {
                EditText editText = (EditText) getChildAt(i);
                if (editText.getText() != null && editText.getText().toString().length() > 0)
                    strEnteredValue = strEnteredValue + editText.getText().toString();
    
            }
            return strEnteredValue;
        }
    
        public void clearCustomEntryEdittext() {
            for (int i = 0; i < getChildCount(); i++) {
                EditText editText = (EditText) getChildAt(i);
                editText.setText("");
            }
            EditText editText = (EditText) getChildAt(0);
            editText.requestFocus();
        }
    }
    
    //and add it in your xml file
    
    <com.custom.widget.CustomEntryEdittext
    android:id=”@+id/custom_unique_edittext”
    android:layout_width=”match_parent”
    android:layout_height=”wrap_content”
    android:layout_alignParentLeft=”true”
    android:layout_centerInParent=”true”
    app:editextCount=”6″>
    </com.custom.widget.CustomEntryEdittext>
    

    For reference check below link

    https://madoverandroid.wordpress.com/2017/07/11/edittext-with-separate-box-for-each-letter-customentryedittext/

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