【问题标题】:Continuous OTP input with EditText使用 EditText 连续 OTP 输入
【发布时间】:2018-07-23 01:40:42
【问题描述】:

这里是 4 EditText 用于输入数字密码。我希望它是这样的,如果第一个 EditText 被 1 个数字填充,那么焦点应该转到下一个 EditText 并且也应该以相反的方式工作。这样用户可以从最左边继续输入密码,也可以从最右边删除相同的方式。

有人可以建议最好的方法吗?

【问题讨论】:

    标签: android android-layout android-edittext android-input-method


    【解决方案1】:

    您无法单独使用 addTextChangedListener 来完成它。您可能必须同时设置 onKeyListener 。这是给你的代码:

    //6 EditTexts are otpEt[0], otpEt[1],...otpEt[5]
    private EditText[] otpEt = new EditText[6];
        otpEt[0] = (EditText) findViewById(R.id.otpEt1);
        otpEt[1] = (EditText) findViewById(R.id.otpEt2);
        otpEt[2] = (EditText) findViewById(R.id.otpEt3);
        otpEt[3] = (EditText) findViewById(R.id.otpEt4);
        otpEt[4] = (EditText) findViewById(R.id.otpEt5);
        otpEt[5] = (EditText) findViewById(R.id.otpEt6);
    
    setOtpEditTextHandler();
    
    private void setOtpEditTextHandler () { //This is the function to be called
        for (int i = 0;i < 6;i++) { //Its designed for 6 digit OTP
            final int iVal = i;
    
            otpEt[iVal].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) {
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    if(iVal == 5 && !otpEt[iVal].getText().toString().isEmpty()) {
                        otpEt[iVal].clearFocus(); //Clears focus when you have entered the last digit of the OTP.
                    } else if (!otpEt[iVal].getText().toString().isEmpty()) {
                        otpEt[iVal+1].requestFocus(); //focuses on the next edittext after a digit is entered.
                    }
                }
            });
    
            otpEt[iVal].setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (event.getAction() != KeyEvent.ACTION_DOWN) {
                        return false; //Dont get confused by this, it is because onKeyListener is called twice and this condition is to avoid it.
                    }
                    if(keyCode == KeyEvent.KEYCODE_DEL && 
    otpEt[iVal].getText().toString().isEmpty() && iVal != 0) {
    //this condition is to handel the delete input by users.
                        otpEt[iVal-1].setText("");//Deletes the digit of OTP
                        otpEt[iVal-1].requestFocus();//and sets the focus on previous digit
                    }
                    return false;
                }
            });
        }
    }
    

    如果您觉得这段代码很难,只需将其粘贴到您的项目中并尝试重新排列即可。您将能够轻松获得它

    【讨论】:

    • 而不是在 for 循环中使用静态数字 6 和 5,如果条件我们可以使用 otpEt.length(otpEt .lengt - 1),它将适用于任何动态的 edtitexts。
    【解决方案2】:

    如果您熟悉RxJava,那么这可能是满足您需求的最简单方法。 这是Kotlin 代码示例

    RxTextView.textChanges(edtOtp1).filter { it.length == 1 }.subscribe { edtOtp2.requestFocus() }
    RxTextView.textChanges(edtOtp2).filter { it.length == 1 }.subscribe { edtOtp3.requestFocus() }
    RxTextView.textChanges(edtOtp3).filter { it.length == 1 }.subscribe { edtOtp4.requestFocus() }
    RxTextView.textChanges(edtOtp4).filter { it.length == 1 }.subscribe { context.hideKeyboard(view) }
    

    你也可以用同样的方式写反向。虽然长度为零,但对上一个 Edittext 的关注。

    【讨论】:

      【解决方案3】:

      您可以使用库Android PinView / OtpView

      或者您可以使用addTextChangedListener 添加一个TextWatcher,每当此EditTextView 的文本发生更改时都会调用它,然后您可以在下一个EditText 上调用View.requestFocus() 来聚焦它

      【讨论】:

        【解决方案4】:

        你可以这样做

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
        
            <EditText
                android:id="@+id/otpET1"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:inputType="number"
                android:maxLength="1"
                android:gravity="center"
                android:textSize="20sp"/>
        
            <EditText
                android:id="@+id/otpET2"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:inputType="number"
                android:maxLength="1"
                android:gravity="center"
                android:textSize="20sp"/>
            <EditText
                android:id="@+id/otpET3"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:inputType="number"
                android:maxLength="1"
                android:gravity="center"
                android:textSize="20sp"/>
        
            <EditText
                android:id="@+id/otpET4"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:inputType="number"
                android:maxLength="1"
                android:gravity="center"
                android:textSize="20sp"/>
            <EditText
                android:id="@+id/otpET5"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:inputType="number"
                android:maxLength="1"
                android:gravity="center"
                android:textSize="20sp"/>
            <EditText
                android:id="@+id/otpET6"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:inputType="number"
                android:gravity="center"
                android:maxLength="1"
                android:textSize="20sp"/>
        </LinearLayout>
        

        活动中

        EditText[] otpETs = new EditText[6];
        
        
        otpETs[0] = findViewById(R.id.otpET1);
        otpETs[1] = findViewById(R.id.otpET2);
        otpETs[2] = findViewById(R.id.otpET3);
        otpETs[3] = findViewById(R.id.otpET4);
        otpETs[4] = findViewById(R.id.otpET5);
        otpETs[5] = findViewById(R.id.otpET6);
        
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            int keyCode = event.getKeyCode();
            if (keyCode == 7 || keyCode == 8 ||
                    keyCode == 9 || keyCode == 10 ||
                    keyCode == 11 || keyCode == 12 ||
                    keyCode == 13 || keyCode == 14 ||
                    keyCode == 15 || keyCode == 16 ||
                    keyCode == 67) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (keyCode == KEYCODE_DEL) {
                        int index = checkWhoHasFocus();
                        if (index != 123) {
                            if (Helpers.rS(otpETs[index]).equals("")) {
                                if (index != 0) {
                                    otpETs[index - 1].requestFocus();
                                }
                            } else {
                                return super.dispatchKeyEvent(event);
                            }
                        }
                    } else {
                        int index = checkWhoHasFocus();
                        if (index != 123) {
                            if (Helpers.rS(otpETs[index]).equals("")) {
                                return super.dispatchKeyEvent(event);
                            } else {
                                if (index != 5) {
                                    otpETs[index + 1].requestFocus();
                                }
                            }
                        }
                        return super.dispatchKeyEvent(event);
                    }
                }
            } else {
                return super.dispatchKeyEvent(event);
            }
            return true;
        }
        
        private int checkWhoHasFocus() {
            for (int i = 0; i < otpETs.length; i++) {
                EditText tempET = otpETs[i];
                if (tempET.hasFocus()) {
                    return i;
                }
            }
            return 123;
        }
        

        这只是从editTexts获取字符串

        public class Helpers {
        
            public static String rS(EditText editText) {
                return editText.getText().toString().trim();
            }
        }
        

        最后,

        String code = Helpers.rS(otpETs[0]) + Helpers.rS(otpETs[1]) + 
        Helpers.rS(otpETs[2]) + Helpers.rS(otpETs[3]) + Helpers.rS(otpETs[4]) 
        + Helpers.rS(otpETs[5]);
        

        或者只使用一个简单的for/while 循环。

        【讨论】:

          【解决方案5】:

          在 Kotlin 中,您可以像 .. 一样使用 bellow

          txtOTP_1.addTextChangedListener(object : TextWatcher {
               override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                   if (txtOTP_1.text.toString().length == 1) {
                       txtOTP_1.clearFocus()
                       txtOTP_2.requestFocus()
                       txtOTP_2.setCursorVisible(true)
                   }
               }
          
               override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
          
               }
          
               override fun afterTextChanged(s: Editable) {
                   if (txtOTP_1.text.toString().length == 0) {
                       txtOTP_1.requestFocus()
                   }
               }
           })
          
          
           txtOTP_2.addTextChangedListener(object : TextWatcher {
               override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                   if (txtOTP_2.text.toString().length == 1) {           
                       txtOTP_2.clearFocus()
                       txtOTP_3.requestFocus()
                       txtOTP_3.setCursorVisible(true)
          
                   }
               }
          
               override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
               }
          
               override fun afterTextChanged(s: Editable) {
                   if (txtOTP_2.text.toString().length == 0) {               
                       txtOTP_2.requestFocus()
                   }
          
               }
           })
          
           txtOTP_3.addTextChangedListener(object : TextWatcher {
               override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                   if (txtOTP_3.text.toString().length == 1) {                
                       txtOTP_3.clearFocus()
                       txtOTP_4.requestFocus()
                       txtOTP_4.setCursorVisible(true)               
                   }
               }
          
               override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
               }
          
               override fun afterTextChanged(s: Editable) {
                   if (txtOTP_3.text.toString().length == 0) {             
                       txtOTP_3.requestFocus()
                   }
          
               }
           })
          
           txtOTP_4.addTextChangedListener(object : TextWatcher {
               override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                   if (txtOTP_4.text.toString().length == 1) {                
                       txtOTP_4.clearFocus()
                       txtOTP_5.requestFocus()
                       txtOTP_5.setCursorVisible(true)
                   }
               }
          
               override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
               }
          
               override fun afterTextChanged(s: Editable) {
                   if (txtOTP_4.text.toString().length == 0) {
                       txtOTP_4.requestFocus()
                   }           
               }
           })
          
          
           txtOTP_5.addTextChangedListener(object : TextWatcher {
               override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                   if (txtOTP_5.text.toString().length == 1) {              
                       txtOTP_5.requestFocus()
                       txtOTP_5.setCursorVisible(true)
          
                   }
               }
            })
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-08-20
            • 2020-05-31
            • 2022-08-16
            • 1970-01-01
            • 2018-05-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多