如何在安卓系统中将焦点切换到下一个编辑框?

36

用户只能在编辑文本框中输入一个数字。如果他在edtText1中输入值,我希望光标自动移动到edtText2等等。用户可以编辑他/她已经输入的文本。我尝试了以下方法。

    edtPasscode1.setOnKeyListener(new OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // TODO Auto-generated method stub
            if (edtPasscode1.getText().length() == 1)
                edtPasscode2.requestFocus();
            return false;
        }
    });

    edtPasscode2.setOnKeyListener(new OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // TODO Auto-generated method stub
            if (edtPasscode2.getText().length() == 1)
                edtPasscode3.requestFocus();
            return false;
        }
    });

    edtPasscode3.setOnKeyListener(new OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            // TODO Auto-generated method stub
            if (edtPasscode3.getText().length() == 1)
                edtPasscode4.requestFocus();
            return false;
        }
    });

如果用户编辑文本,光标会移动到其他的editTexts而不是按预期工作。我该如何实现上述功能?


你所有的视图必须在一个单一的父级视图中才能获得正确的焦点。请检查布局父级视图。 - Jitender Dev
@Brontok 是的,它在单个父级中。它们全部都在一个线性布局中,水平对齐。 - Rethinavel
可能是Android中的EditText焦点问题的重复问题。 - Alfredo Cavalcanti
2
用户只能在编辑文本中输入一个数字。如果他在edtText1中输入了值,我希望光标自动移动到edtText2等等。为什么不使用单个EditText? - gunar
9个回答

46
尝试使用 TextWatcher 代替 onKeyListener,因为如果想要编辑密码,在这种情况下,TextWatcher将会提供更多的方法来处理。
StringBuilder sb=new StringBuilder();

         edtPasscode1.addTextChangedListener(new TextWatcher() {
             public void onTextChanged(CharSequence s, int start, int before, int count) {
                 // TODO Auto-generated method stub
                 if(sb.length()==0&edtPasscode1.length()==1)
                 {
                     sb.append(s);
                     edtPasscode1.clearFocus();
                     edtPasscode2.requestFocus();
                     edtPasscode2.setCursorVisible(true);

                 }
             }

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

                 if(sb.length()==1)
                 {

                     sb.deleteCharAt(0);

                 }

             }

             public void afterTextChanged(Editable s) {
                 if(sb.length()==0)
                 {

                     edtPasscode1.requestFocus();
                 }

             }
         });

希望这个工作顺利。


@RethinavelVelu,请查看我的更新答案。通过这个,你也可以编辑你的密码。 - Amit Gupta
@ Amit Gupta。谢谢老板。我早上就在找这个。它运行得非常好。很高兴接受你的答案并感谢你回答这个问题。 - Rethinavel
@Amit Gupta,谢谢你的回答。但是当你删除字符时,如何返回到先前的EditText? - Androider

13

在xml中将android:maxLength="1"设置给所有的ExitText

尝试以下代码

edtxt1 = (EditText) findViewById(R.id.edtxt_phonenumber_one);
        edtxt2 = (EditText) findViewById(R.id.edtxt_phonenumber_two);
        edtxt3 = (EditText) findViewById(R.id.edtxt_phonenumber_three);

        edtxt1.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {

                if (s.length() ==1) {
                    edtxt2.requestFocus();
                }

            }

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

            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
            }
        });

        edtxt2.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
                if (s.length() == 1) {
                    edtxt3.requestFocus();
                }

            }

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

            }

            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {

            }
        });
        edtxt3.addTextChangedListener(new TextWatcher() {
            public void afterTextChanged(Editable s) {
                if (s.length() == 1) {
                    edtxt1.requestFocus();
                }

            }

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

            }

            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {

            }
        });

这应该可以工作


4

将editetxt的长度设置为android:maxLength="1",并按照以下代码进行操作

((EditText) findViewById(R.id.edi1)).addTextChangedListener(new TextWatcher() {
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub
            if(((EditText) findViewById(R.id.edi1)).getText().toString().length()==1)
            {
                ((EditText) findViewById(R.id.edi1)).clearFocus();
                ((EditText) findViewById(R.id.edi2)).requestFocus();
                ((EditText) findViewById(R.id.edi2)).setCursorVisible(true);

            }
        }

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

            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub

        }


    });

    ((EditText) findViewById(R.id.edi2)).addTextChangedListener(new TextWatcher() {
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub
            if(((EditText) findViewById(R.id.edi2)).getText().toString().length()==1)
            {
                ((EditText) findViewById(R.id.edi2)).clearFocus();
                ((EditText) findViewById(R.id.edi3)).requestFocus();
                ((EditText) findViewById(R.id.edi3)).setCursorVisible(true);

            }
        }

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

            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub

        }


    });


    ((EditText) findViewById(R.id.edi3)).addTextChangedListener(new TextWatcher() {
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub
            if(((EditText) findViewById(R.id.edi3)).getText().toString().length()==1)
            {
                ((EditText) findViewById(R.id.edi3)).clearFocus();
                ((EditText) findViewById(R.id.edi4)).requestFocus();
                ((EditText) findViewById(R.id.edi4)).setCursorVisible(true);

            }
        }

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

            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub

        }


    });

4

首先,设置EditText max length=1,在这里我在xml文件中使用了三个EditText

<EditText
    android:id="@+id/edt1"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:inputType="number"
    android:textAlignment="center"
    android:singleLine="true"
    android:maxLength="1"
    android:maxLines="1"
    android:imeOptions="actionNext"
    android:layout_margin="5dp"
    android:background="@drawable/edittext_shape_bg"/>


<EditText
    android:id="@+id/edt2"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:inputType="number"
    android:textAlignment="center"
    android:singleLine="true"
    android:maxLength="1"
    android:imeOptions="actionNext"
    android:maxLines="1"
    android:layout_margin="5dp"
    android:background="@drawable/edittext_shape_bg"/>

<EditText
    android:id="@+id/edt3"
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:inputType="number"
    android:textAlignment="center"
    android:singleLine="true"
    android:maxLength="1"
    android:imeOptions="actionNext"
    android:maxLines="1"
    android:layout_margin="5dp"
    android:background="@drawable/edittext_shape_bg"/>

接着,在每个EditText中实现addTextChangeListener,它可以帮助您前进和后退。

这里我们使用StringBuilder来获取最终字符串值。

edt1.addTextChangedListener(new TextWatcher() {
      @Override
      public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

      }

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

      }

      @Override
      public void afterTextChanged(Editable editable) {
          String edtChar=edt1.getText().toString();
          if(edtChar.length()==1)
          {
              currentCode.append(edtChar);

              edt2.requestFocus();
          }else if(edtChar.length()==0) {
            currentCode.deleteCharAt(0);
              edt1.requestFocus();
          }


      }
  });


    edt2.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

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

        }

        @Override
        public void afterTextChanged(Editable editable) {
            String edtChar=edt2.getText().toString();
            if(edtChar.length()==1)
            {
                currentCode.append(edtChar);

                edt3.requestFocus();
            }else if(edtChar.length()==0) {
                currentCode.deleteCharAt(1);
                edt1.requestFocus();
            }


        }
    });
    edt3.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

        }

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

        }

        @Override
        public void afterTextChanged(Editable editable) {
            String edtChar=edt3.getText().toString();
            if(edtChar.length()==1)
            {
                currentCode.append(edtChar);

                edt4.requestFocus();
            }else if(edtChar.length()==0) {
                currentCode.deleteCharAt(2);
                edt2.requestFocus();
            }


        }
    });

1
这对我的情况有效,同时编辑文本的最大长度应为1。
otp_1.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    //
                }

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

            }

            @Override
            public void afterTextChanged(Editable editable) {
                //
                if(editable.length()>0){
                    otp_1.clearFocus();
                    otp_2.requestFocus();
                    otp_2.setCursorVisible(true);
                }
            }
        });

        otp_2.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                //
            }

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

            }

            @Override
            public void afterTextChanged(Editable editable) {
                //
                if(editable.length() > 0) {
                    otp_2.clearFocus();
                    otp_3.requestFocus();
                    otp_3.setCursorVisible(true);
                }
            }
        });

        otp_3.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                //
            }

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

            }

            @Override
            public void afterTextChanged(Editable editable) {
                if(editable.length() > 0) {
                    otp_3.clearFocus();
                    otp_4.requestFocus();
                    otp_4.setCursorVisible(true);
                }
            }
        });

0

这是我的 Kotlin 解决方案

private fun addEditTextListener(editText: EditText?, nextEditText: EditText?) {
    editText?.setOnFocusChangeListener { view, focused ->
        if (focused) {
            editText.text = null
        }
    }
    editText?.addTextChangedListener {
        if (it.toString().isNotEmpty()) {
            if (nextEditText != null) {
                nextEditText.requestFocus()
            } else {
                viewModel.confirmCode(
                    binding?.digit1?.text?.toString(),
                    binding?.digit2?.text?.toString(),
                    binding?.digit3?.text?.toString(),
                    binding?.digit4?.text?.toString(),
                )
            }
        }

    }
}

并设置监听器

 override fun setupViews() {
    addEditTextListener(binding?.digit1, binding?.digit2)
    addEditTextListener(binding?.digit2, binding?.digit3)
    addEditTextListener(binding?.digit3, binding?.digit4)
    addEditTextListener(binding?.digit4, null)
}

0

我之前也遇到了同样的问题,但是我已经解决了,方法很简单。 使用.xml文件,使用android:nextFocusDown="next_EditText_id"

例如:

<EditText
       android:id="@+id/edtUsername"
       android:nextFocusDown="@id/edtPassword"
       style="@style/EditText"
       />

<EditText
       android:id="@+id/edtPassword"
       style="@style/EditText.Password"
       />

-1

解决方案的编码是正确的,

下面的代码表示自动移动到下一个编辑文本和自动移动到上一个编辑文本。

如果您在以下情况下使用 Rxjava + Data Binding + RxBinding,也可以正常工作:

// Show button Active code when enough fields active code
    Observable<Boolean> mObsPhoneVerify1 = RxTextView.textChanges(db.etPhoneVerify1)
            .observeOn(AndroidSchedulers.mainThread())
            .map(charSequence -> {
                if (!charSequence.toString().equals("")) {
                    db.etPhoneVerify2.requestFocus();
                    return true;
                } else {
                    db.etPhoneVerify1.requestFocus();
                    return false;
                }
            });
    Observable<Boolean> mObsPhoneVerify2 = RxTextView.textChanges(db.etPhoneVerify2)
            .observeOn(AndroidSchedulers.mainThread())
            .map(charSequence -> {
                if (!charSequence.toString().equals("")) {
                    db.etPhoneVerify3.requestFocus();
                    return true;
                } else {
                    db.etPhoneVerify1.requestFocus();
                    return false;
                }
            });
    Observable<Boolean> mObsPhoneVerify3 = RxTextView.textChanges(db.etPhoneVerify3)
            .observeOn(AndroidSchedulers.mainThread())
            .map(charSequence -> {
                if (!charSequence.toString().equals("")) {
                    db.etPhoneVerify4.requestFocus();
                    return true;
                } else {
                    db.etPhoneVerify2.requestFocus();
                    return false;
                }
            });
    Observable<Boolean> mObsPhoneVerify4 = RxTextView.textChanges(db.etPhoneVerify4)
            .observeOn(AndroidSchedulers.mainThread())
            .map(charSequence -> {
                if (!charSequence.toString().equals("")) {
                    hideKeyboard();
                    return true;
                } else {
                    /*
                    If enough text for  all fields, no need cursor
                    Otherwise, focus previous edit text
                     */
                    if (Utils.isValidEditText(db.etPhoneVerify1) && Utils.isValidEditText(db.etPhoneVerify2) && Utils.isValidEditText(db.etPhoneVerify3)) {
                        db.etPhoneVerify3.requestFocus();
                    } else {
                        db.etPhoneVerify1.clearFocus();
                        db.etPhoneVerify2.clearFocus();
                        db.etPhoneVerify3.clearFocus();
                        db.etPhoneVerify4.clearFocus();
                    }
                    return false;
                }
            });

   disposable = Observable
            .combineLatest(mObsPhoneVerify1, mObsPhoneVerify2, mObsPhoneVerify3, mObsPhoneVerify4,
                    (PhoneVerify1, PhoneVerify2, PhoneVerify3, PhoneVerify4)
                            -> PhoneVerify1 && PhoneVerify2 && PhoneVerify3 && PhoneVerify4)
            .compose(regisObserver(false))
            .subscribe(aBoolean -> {
                db.btnActiveCode.setEnabled(aBoolean);
            });

-2

您可以使用隐藏的 EditText 接收输入,四个 TextView 来显示密码。

例如:

dialog_passworld.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="10dip"
    android:paddingLeft="20dip"
    android:paddingRight="20dip"
    android:paddingTop="10dip" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Please enter a password"
        android:textSize="16sp" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="40dip"
        android:layout_marginTop="15dip" >

        <EditText
            android:id="@+id/passcode"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <LinearLayout
            android:id="@+id/passcode_container"
            android:layout_width="match_parent"
            android:layout_height="40dip"
            android:background="@drawable/password_border" >

            <TextView
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@android:color/transparent"
                android:gravity="center"
                android:textSize="18sp"
                android:textStyle="bold" />

            <View
                android:layout_width="1px"
                android:layout_height="match_parent"
                android:background="@android:color/darker_gray" />

            <TextView
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@android:color/transparent"
                android:gravity="center"
                android:textSize="16sp"
                android:textStyle="bold" />

            <View
                android:layout_width="1px"
                android:layout_height="match_parent"
                android:background="@android:color/darker_gray" />

            <TextView
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@android:color/transparent"
                android:gravity="center"
                android:textSize="16sp"
                android:textStyle="bold" />

            <View
                android:layout_width="1px"
                android:layout_height="match_parent"
                android:background="@android:color/darker_gray" />

            <TextView
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@android:color/transparent"
                android:gravity="center"
                android:textSize="16sp"
                android:textStyle="bold" />
        </LinearLayout>
    </FrameLayout>

</LinearLayout>

PasswordDialogBuilder.java

public class PasswordDialogBuilder extends AlertDialog.Builder {

    public PasswordDialogBuilder(Context context) {
        super(context, displayMetrics, eventManager);

        View contentView = LayoutInflater.from(context).inflate(R.layout.dialog_password, null);

        LinearLayout passcodeContainer = (LinearLayout) contentView.findViewById(R.id.passcode_container);

        final List<TextView> passwordViews = new ArrayList<TextView>();

        int childCount = passcodeContainer.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childView = passcodeContainer.getChildAt(i);
            if (childView instanceof TextView) {
                passwordViews.add((TextView) childView);
            }
        }

        final int passwordCount = passwordViews.size();

        EditText passwordView = (EditText) contentView.findViewById(R.id.passcode);
        passwordView.setFilters(new InputFilter[] {new InputFilter.LengthFilter(passwordCount)});
        passwordView.setInputType(EditorInfo.TYPE_CLASS_NUMBER);
        passwordView.setCursorVisible(false);
        passwordView.setTextColor(Color.TRANSPARENT);
        passwordView.setBackgroundColor(Color.TRANSPARENT);
        passwordView.setSingleLine();

        passwordView.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}

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

            @Override
            public void afterTextChanged(Editable s) {
                int passwordLength = s.length();

                for (int i = 0; i < passwordCount; i++) {
                    TextView passcodeView = passwordViews.get(i);
                    if (i < passwordLength) {
                        passcodeView.setText(String.valueOf(s.charAt(i)));
                    } else {
                        passcodeView.setText(StringUtils.EMPTY);
                    }
                }

                if (positiveButton != null) {
                    positiveButton.setEnabled(passwordLength == passwordCount);
                }
            }
        });

        setView(contentView);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接