嗨,我正在开发一个应用程序,当用户想要重置他的密码时,要求OTP,我需要一个像附加图像中那样的文本...我想继续的是每个字母的单独文本,全部它们排列成水平方向的线性布局,有一些边距......最大长度为1,因此每个editText只能输入一个字母......这是一个正确的方法吗?有什么建议??
您可以通过使TextWatcher更通用来尝试这一点,因此它易于使用和理解
使用以下课程:
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.editText1:
if(text.length()==1)
et2.requestFocus();
break;
case R.id.editText2:
if(text.length()==1)
et3.requestFocus();
else if(text.length()==0)
et1.requestFocus();
break;
case R.id.editText3:
if(text.length()==1)
et4.requestFocus();
else if(text.length()==0)
et2.requestFocus();
break;
case R.id.editText4:
if(text.length()==0)
et3.requestFocus();
break;
}
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
}
如何使用上面的课程
et1.addTextChangedListener(new GenericTextWatcher(et1));
et2.addTextChangedListener(new GenericTextWatcher(et2));
et3.addTextChangedListener(new GenericTextWatcher(et3));
et4.addTextChangedListener(new GenericTextWatcher(et4));
这里et1,et2,et3和et4是你的EditTexts,我知道它根据Java标准的错误命名约定,但你可以用你的替换它。
P.S你可以在这里找到xml设计GitHub some other, sample design xml for reference
使用DataBinding布局:
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;
}
}
您可以继承TextWatcher并实现自己的逻辑。
public class OTPTextWatcher implements TextWatcher {
private EditText view;
private List<EditText> otpDigitViews;
private OTPListener otpListener;
public OTPTextWatcher(EditText otpView, List<EditText> otpDigitViews, OTPListener listener) {
view = otpView;
this.otpDigitViews = otpDigitViews;
this.otpListener = listener;
}
@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 digit1 = otpDigitViews.get(0).getText().toString();
String digit2 = otpDigitViews.get(1).getText().toString();
String digit3 = otpDigitViews.get(2).getText().toString();
String digit4 = otpDigitViews.get(3).getText().toString();
String currentDigit = editable.toString();
final String inputValue = digit1 + digit2 + digit3 + digit4;
if (inputValue.length() == 4) {
if (inputValue.equals("1234")) {
otpListener.onOTPSuccess();
} else {
otpListener.onOTPError();
}
} else {
if (currentDigit.length() >= 1
&& view != otpDigitViews.get(3)) {
if (view != null)
view.focusSearch(View.FOCUS_RIGHT).requestFocus();
} else {
if (currentDigit.length() <= 0 && view.getSelectionStart() <= 0) {
try {
view.focusSearch(View.FOCUS_LEFT).requestFocus();
} catch (NullPointerException e) {
LogHelper.printErrorLog("There is not view left to current edit text");
}
}
}
}
}
public interface OTPListener {
void onOTPSuccess();
void onOTPError();
}
}
OtpEditText.java(自定义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;
}
}
}
}
在XML中使用此自定义的EditText,如下所示:
<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"/>
参考: 文章:https://medium.com/@ali.muzaffar/building-a-pinentryedittext-in-android-5f2eddcae5d3 示例代码:https://gist.github.com/alphamu/0d3055e0233c5749b8d6
我基于其他答案实现了以下代码。
我希望这些代码非常简单,优化并且可以理解变化。
不要在你的xml中使用android:maxLength="1"
。
//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;
}
}
}
使用4个不同的EditText。使用以下代码在后续输入后更改焦点。
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) {
}
});
等等...
连接所有EditText中的文本。
我为6位OTP制作了一个通用的TextWatcher:
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));
}
}
您可以将此textWatcher添加到所有编辑文本中,如下所示:
this.otpEdit1.addTextChangedListener(new GenericTextWatcher(otpEdit1));
以下解决方案考虑到:
onTextChanged()和afterTextChanged()中的工作组合有助于实现相同的目标。
private EditText firstDigitOtpEdt, secondDigitOtpEdt, thirdDigitOtpEdt, fourthDigitOtpEdt;
firstDigitOtpEdt.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 (firstDigitOtpEdt.getText().toString().length() == 1) {
secondDigitOtpEdt.requestFocus();
}
}
});
secondDigitOtpEdt.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) {
if (secondDigitOtpEdt.getText().toString().length() == 0) {
firstDigitOtpEdt.requestFocus();
}
}
@Override
public void afterTextChanged(Editable editable) {
if (secondDigitOtpEdt.getText().toString().length() == 1) {
thirdDigitOtpEdt.requestFocus();
}
}
});
thirdDigitOtpEdt.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) {
if (thirdDigitOtpEdt.getText().toString().length() == 0) {
secondDigitOtpEdt.requestFocus();
}
}
@Override
public void afterTextChanged(Editable editable) {
if (thirdDigitOtpEdt.getText().toString().length() == 1) {
fourthDigitOtpEdt.requestFocus();
}
}
});
fourthDigitOtpEdt.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) {
if (fourthDigitOtpEdt.getText().toString().length() == 0) {
thirdDigitOtpEdt.requestFocus();
}
}
@Override
public void afterTextChanged(Editable editable) {
// We can call api to verify the OTP here or on an explicit button click
}
});
你可以尝试这个,如果你想添加一些额外的逻辑来删除OTP,我根据A.R的答案创建它。确保为所有edittext设置maxlength = 2
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) {
}
}
使用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;
}
}
}
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) {
}
}
接下来,我们在每个edittext上添加addTextChangedListener。
e1.addTextChangedListener(GenericTextWatcher(e2, e1))
e2.addTextChangedListener(GenericTextWatcher(e3, e1))
e3.addTextChangedListener(GenericTextWatcher(e4, e2))
e4.addTextChangedListener(GenericTextWatcher(e5, e3))
e5.addTextChangedListener(GenericTextWatcher(e6, e4))
e6.addTextChangedListener(GenericTextWatcher(e6, e5))
您可以制作自定义Editext并将其添加到xml文件中,在下面找到自定义类
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>
供参考检查以下链接