I have three EditText Boxes, that has the following requirements: -
- Should not allow User Touch and should be navigated only using the 'Enter Key' and the Backspace buttons.
Each Edit Texts can have 2 characters, once filled up, it should automatically focus to the next EditText box on right (View.FOCUS_RIGHT) (currently I am using TextWatcher to detect this).
If the User presses backspaces and the current EditText box is empty, the focus should be moved to the previous EditText box (View.FOCUS_LEFT).
- If the current EditText has Maximum characters (2), and the user keys in a new character, the focus should be shifted to the next (right) EditText and the newly entered character should be inserted into the newly focused EditText.
Here is the code that I have:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.multitiext.mutlitextviewapp.MainActivity">
<TextView
android:id="@+id/tv_text_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentStart="true"
android:layout_below="@+id/tv_text_display"
android:layout_marginTop="40dp"
android:orientation="horizontal">
<com.multitiext.mutlitextviewapp.custom.MyEditText
android:id="@+id/et_input01"
android:layout_width="60dp"
android:layout_height="match_parent"
android:inputType="textCapWords"
android:imeOptions="actionNext"
android:maxLength="@integer/max_length_per_edit_text"
android:selectAllOnFocus="true"/>
<com.multitiext.mutlitextviewapp.custom.MyEditText
android:id="@+id/et_input02"
android:layout_width="60dp"
android:layout_height="match_parent"
android:inputType="textCapWords"
android:imeOptions="actionNext"
android:maxLength="@integer/max_length_per_edit_text"
android:selectAllOnFocus="true" />
<com.multitiext.mutlitextviewapp.custom.MyEditText
android:id="@+id/et_input03"
android:layout_width="60dp"
android:layout_height="match_parent"
android:inputType="textCapWords"
android:imeOptions="actionDone"
android:maxLength="@integer/max_length_per_edit_text"
android:selectAllOnFocus="true" />
</LinearLayout>
</RelativeLayout>`
Here is my Activity with the Three EditText fields:
`public class MainActivity extends AppCompatActivity {
private MyEditText et_input01;
private MyEditText et_input02;
private MyEditText et_input03;
private TextView tv_display01;
private String fullText;
private View nextET = null;
private EditText currentET = null;
private Integer maxLengthPerEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUI();
setInitialFocus();
setListeners();
showSoftKeyboard();
}
private void initUI() {
et_input01 = (MyEditText) findViewById(R.id.et_input01);
et_input02 = (MyEditText) findViewById(R.id.et_input02);
et_input03 = (MyEditText) findViewById(R.id.et_input03);
et_input01.setCurrentET(et_input01);
et_input02.setCurrentET(et_input02);
et_input03.setCurrentET(et_input03);
tv_display01 = (TextView) findViewById(R.id.tv_text_display);
maxLengthPerEditText = getResources().getInteger(R.integer.max_length_per_edit_text);
}
private void setListeners() {
InputFilter[] inputFilters = new InputFilter[] {new InputFilter.AllCaps()
};
et_input01.setFilters(inputFilters);
et_input02.setFilters(inputFilters);
et_input03.setFilters(inputFilters);
Log.i(MainActivity.class.getName(), "Adding listeners");
et_input03.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
fullText = (new StringBuilder(et_input01.getText().toString()))
.append(et_input02.getText().toString())
.append(et_input03.getText().toString())
.toString();
tv_display01.setText(fullText);
}
if (event.getKeyCode()==KeyEvent.ACTION_UP && event.getAction() == KeyEvent.KEYCODE_DEL){
et_input02.requestFocus();
}
return false;
}
});
et_input02.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (event.getKeyCode()==KeyEvent.ACTION_UP && event.getAction() == KeyEvent.KEYCODE_DEL) {
et_input01.requestFocus();
}
return false;
}
});
et_input01.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
nextET = null;
currentET = et_input01;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
Log.i("MainActivity", "et01: " + s.toString());
String currentText = s.toString();
int currentTextLength = currentText.length();
String newText = "";
String moveToNextString = "";
if (currentTextLength == maxLengthPerEditText) {
nextET = currentET.focusSearch(View.FOCUS_RIGHT);
}
if (currentTextLength == 0) {
}
if (currentTextLength > maxLengthPerEditText) {
newText = (currentText).substring(0, maxLengthPerEditText);
moveToNextString = (currentText).substring(maxLengthPerEditText);
currentET.setText(newText);
nextET = currentET.focusSearch(View.FOCUS_RIGHT);
if (nextET != null && nextET instanceof EditText) {
((EditText) nextET).setText(moveToNextString);
}
}
if (nextET != null && nextET instanceof EditText) {
nextET.requestFocus();
}
}
});
et_input02.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
nextET = null;
currentET = et_input02;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
Log.i("MainActivity", "et02: " + s.toString());
String currentText = s.toString();
int currentTextLength = currentText.length();
String newText = "";
String moveToNextString = "";
if (currentTextLength == maxLengthPerEditText) {
nextET = currentET.focusSearch(View.FOCUS_RIGHT);
}
if (currentTextLength == 0) {
nextET = currentET.focusSearch(View.FOCUS_LEFT);
}
if (currentTextLength > maxLengthPerEditText) {
newText = (currentText).substring(0, maxLengthPerEditText);
moveToNextString = (currentText).substring(maxLengthPerEditText);
currentET.setText(newText);
nextET = currentET.focusSearch(View.FOCUS_RIGHT);
if (nextET != null && nextET instanceof EditText) {
((EditText) nextET).setText(moveToNextString);
}
}
if (nextET != null && nextET instanceof EditText) {
nextET.requestFocus();
}
}
});
et_input03.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
nextET = null;
currentET = et_input03;
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
Log.i("MainActivity", "et03: " + s.toString());
String currentText = s.toString();
int currentTextLength = currentText.length();
String newText = "";
if (currentTextLength == maxLengthPerEditText) {
}
if (currentTextLength == 0) {
nextET = currentET.focusSearch(View.FOCUS_LEFT);
}
if (currentTextLength > maxLengthPerEditText) {
newText = (currentText).substring(0, maxLengthPerEditText);
currentET.setText(newText);
}
if (nextET != null && nextET instanceof EditText) {
nextET.requestFocus();
}
}
});
}
private void setInitialFocus() {
et_input01.requestFocus();
}
private void showSoftKeyboard() {
InputMethodManager imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
}
}`
I have a customized EditText to detect backspace, but it currently cannot be used to move to the previous EditText field, if the current field is empty (From an answer here: Android EditText delete(backspace) key event).
public class MyEditText extends EditText {
private MyEditText currentET;
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyEditText(Context context) {
super(context);
}
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setCurrentET(MyEditText currentET) {
this.currentET = currentET;
}
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
return new MyInputConnection(super.onCreateInputConnection(outAttrs),
true);
}
private class MyInputConnection extends InputConnectionWrapper {
public MyInputConnection(InputConnection target, boolean mutable) {
super(target, mutable);
}
@Override
public boolean sendKeyEvent(KeyEvent event) {
return super.sendKeyEvent(event);
}
@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
if (beforeLength == 1 && afterLength == 0) {
return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
}
return super.deleteSurroundingText(beforeLength, afterLength);
}
}
}`
The issues that I am currently seeing are: - if the EditText is empty and if the Backspace is pressed, the previous EditText is not selected. - Is there a much simpler way to achieve the requirements here?