5

I am trying to make Pin entering page and I created 4 EditTexts and I created a function which is below in my activity. My problem is when i click backspace button I want to focus Current EditText to Before(Back) EditText but Key listener not works.

the logic is simple, when user enters a number to edittext, it losts focus and next edittext is getting focus then it goes like that. but the problem is when I click back space I want to go back before edittext to enter number again. I tried to insert keyListener inside of beforeTextChange but it is not worked.

 private void SetTextChange(final EditText etCurrent, final EditText etForward,final EditText etBack, final boolean isLast, final int currentPosition)
{

    etCurrent.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) {

            if (etCurrent.getText().length() == 1 && !isLast ) {
                etCurrent.setTypeface(null, Typeface.NORMAL);
                etCurrent.clearFocus();
                etForward.requestFocus();
                etForward.setCursorVisible(true);

                etCurrent.getBackground().setColorFilter(getResources().getColor(R.color.lavender_indigo), PorterDuff.Mode.SRC_ATOP);
            } else if (etCurrent.length() == 0) {
                etCurrent.getBackground().setColorFilter(getResources().getColor(R.color.french_gray), PorterDuff.Mode.SRC_ATOP);
                etCurrent.setTypeface(null, Typeface.SANS_SERIF.getStyle());

                etCurrent.setTypeface(null, Typeface.NORMAL);
                etCurrent.clearFocus();
                etBack.requestFocus();
                etBack.setCursorVisible(true);

            }


            if (etCurrent.length() != 0) {
                Integer currentKey = Integer.parseInt(etCurrent.getText().toString());
                keyList.set(currentPosition, currentKey);
            } else
                keyList.set(currentPosition, -1);

            if (keyList.size() > 3)
                showToast(keyList.get(0) + " " + keyList.get(1) + " " + keyList.get(2) + " " + keyList.get(3));

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

    /*curText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        public void onFocusChange(View arg0, boolean arg1) {
            curText = etCurrent;
            backText = etBack;
            curText.setText("");
        }

        });*/
    }

This is also one of my EditText sample xml.(Others are the same)

  <EditText
        android:layout_column="1"
        android:layout_columnWeight="1"
        android:id="@+id/etActivationDigit1"
        android:layout_width="70dp"
        android:layout_height="wrap_content"
        android:textSize="80dp"
        android:textAlignment="center"
        android:gravity="center_horizontal"
        android:hint="*"
        android:textColorHint="@color/french_gray"
        android:backgroundTint="@color/french_gray"
        android:fontFamily="sans-serif"
        android:textColor="@color/perfume"
        android:maxLength="1"
        android:inputType="number"
         />

I just wanted to erase and focus back when user enters wrong number. Attention : when you fill all fields you will see you can delete and go back but I want to go back middle of pin code. Thank you.

  etCurrent.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if(etCurrent.getText().toString() == "" && keyCode == event.KEYCODE_DEL)
            {
                etCurrent.setText("");
                etCurrent.clearFocus();
                etBack.requestFocus();
                etBack.setText("");
            }
            return false;
        }
    });

My Backspace listener not triggers when I touch backspace but it triggers all other characters.

MMG
  • 3,226
  • 5
  • 16
  • 43
Colibri
  • 537
  • 5
  • 8
  • put condition on onTextChanged. if edittext is empty then set focus on previous edittext – Chirag Savsani Oct 28 '15 at 08:05
  • 1
    But the condition is when user is enters wrong number, maybe he/she on the 3. EditText but he/she realize that the first Edittext entered wrong, so he must go back with backspace.(By the way on touch focus will be false.) – Colibri Oct 28 '15 at 08:11

6 Answers6

2

This is what worked for my 4-digit pin code activity.

private void setupInputListeners() {
    verificationCode1EditText.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) {
            if (s.length() == 1) {
                verificationCode2EditText.requestFocus(View.FOCUS_DOWN);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    });

    verificationCode2EditText.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) {
            if(count == 0) {
                verificationCode1EditText.requestFocus(View.FOCUS_DOWN);
            } else {
                if (s.length() == 1) {
                    verificationCode3EditText.requestFocus(View.FOCUS_DOWN);
                }
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    });

    verificationCode3EditText.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) {
            if(count == 0) {
                verificationCode2EditText.requestFocus(View.FOCUS_DOWN);
            } else {
                if (s.length() == 1) {
                    verificationCode4EditText.requestFocus(View.FOCUS_DOWN);
                }
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    });

    verificationCode4EditText.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) {
            if(count == 0) {
                verificationCode3EditText.requestFocus(View.FOCUS_DOWN);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    });
}
Woppi
  • 5,303
  • 11
  • 57
  • 81
  • 1
    If a text is deleted with Delete or selecting and removing (with cut tool), should a cursor move to a previous control? – CoolMind Oct 04 '18 at 14:23
  • 1
    @CoolMind, I don't think so. it should stay on the deleted cursor position. – Woppi Oct 05 '18 at 07:17
  • 1
    @Woppi, agree. But as I see in the code, after removing a symbol in any way a cursor will leave current position. – CoolMind Oct 05 '18 at 07:31
  • @CoolMind, oh really. Sorry, I have forgotten it. It's been a long time since I did any android development. :) You can just tweak it to your liking. :) – Woppi Oct 08 '18 at 10:00
  • 2
    @Woppi, and what are you doing these days? :) Don't leave Android dev :) Yes, now I also use `setOnKeyListener` and check `keyCode == KeyEvent.KEYCODE_DEL` with text.isEmpty(). Maybe will edit your answer. – CoolMind Oct 08 '18 at 10:07
  • 1
    @CoolMind, nice glad you figure it out. The company I worked for moved me to a totally different project. I'm doing NodeJS + Apollo GraphQL now. :) So when I look at my android project... I can't remember how and why I did it. It's been a year. :) – Woppi Oct 08 '18 at 10:16
  • @Woppi, wish you success! I also appreciate Philippines people and want to visit your country. :) – CoolMind Oct 08 '18 at 10:19
  • 1
    @CoolMind, I wish you success as well. If you're into snorkeling and island tripping you should visit and checkout either Caramoan, Palawan, Anilao, or Davao :) Thanks! – Woppi Oct 08 '18 at 10:25
  • Hi, thanks for the answer and discussion about it in comments. I modified the answer and it it like @CoolMind opinion. But I have a problem. Some keyboards like https://play.google.com/store/search?q=gokeyboard&c=apps&hl=en doesn't detect KEYCODE_DEL. So when I can't jump to previous edittext with pressing DELETE key. What I should I do for handling that? I asked a question about it yesterday:https://stackoverflow.com/q/62788914/12478830 – MMG Jul 09 '20 at 04:15
1

just add this code in your editText onTextChanged method

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(yourEditText.length()==0){
                priviousEditText.requestFocus();
            }
}
0

Have a look at this.
MainActivity.java

    public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final EditText one = (EditText) findViewById(R.id.edtOne);
        final EditText two = (EditText) findViewById(R.id.edtTwo);
        final EditText three = (EditText) findViewById(R.id.edtThree);
        final EditText four = (EditText) findViewById(R.id.edtFour);

        one.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
                // TODO Auto-generated method stub

            }

            @Override
            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

            }
        });
        two.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
                if(s.toString().trim().length() == 0){
                    one.requestFocus();
                    one.setSelection(one.getText().toString().length());
                }

            }

            @Override
            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

            }
        });
        three.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
                if(s.toString().trim().length() == 0){
                    two.requestFocus();
                    two.setSelection(two.getText().toString().length());
                }

            }

            @Override
            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

            }
        });
        four.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence s, int start, int before,
                    int count) {
                if(s.toString().trim().length() == 0){
                    three.requestFocus();
                    three.setSelection(three.getText().toString().length());
                }

            }

            @Override
            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

            }
        });


    }


}

// Use this code as a reference.

customDialog.setOnKeyListener(new OnKeyListener() {

            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {

                if (event.getAction() != KeyEvent.ACTION_DOWN) {
                    if (keyCode == KeyEvent.KEYCODE_BACK) {
                        customDialog.dismiss();
                        HomeActivity.this.finish();
                    } else if (keyCode == KeyEvent.KEYCODE_DEL) {
                        if (!pin3.getText().toString().equals("")) {
                            pin3.setText("");
                            pin3.requestFocus();
                        } else if (!pin2.getText().toString().equals("")) {
                            pin2.setText("");
                            pin2.requestFocus();
                        } else if (!pin1.getText().toString().equals("")) {
                            pin1.setText("");
                            pin1.requestFocus();
                        }
                    }
                }
                return true;
            }
        });
        return customDialog;

I use this code in my application and it works completely.

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <EditText
        android:id="@+id/edtOne"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="0" />
    <EditText
        android:id="@+id/edtTwo"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="2" />
    <EditText
        android:id="@+id/edtThree"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="3" />
    <EditText
        android:id="@+id/edtFour"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:text="4" />

</LinearLayout>
Chirag Savsani
  • 6,020
  • 4
  • 38
  • 74
  • This is not answer that what I wanted. My example is When I am focused on 3. EditText, I realized that "Oww I entered wrong number to 1. EditText let me go back and Click backspace and going 2. EditText then I am clicking backspace again and I am on first EditText so I can rewrite my pin" The real life example like that. – Colibri Oct 28 '15 at 08:36
  • The example that I have given does exactly same thing that you are saying. – Chirag Savsani Oct 28 '15 at 08:40
  • When I enter a number to second EditText, focus automatically shifts to third one and when I click backspace it is not working, because I am not doing any text change event on third EditText, therefore even if i put breakpoint in third one's OnTextChange method it wont catch it. – Colibri Oct 28 '15 at 09:28
  • Ok I understand. In my app I create one custom dialog for enter four digit pin number. and when user press backspace all four pin number will be removed one by one. – Chirag Savsani Oct 28 '15 at 09:48
  • Actually I only need to catch backspace button click, but interestingly my KeyListener catches all numbers etc. except backspace. It is not triggers when I touch backspace. – Colibri Oct 28 '15 at 09:50
  • Yes, we are thinking exacly the same thing but the problem is OnKeyListener catches like 5,3,4 etc. keys but when I touch backspace it is not going in listener, it is not acting or doing anything when I click on it. I updated my question. – Colibri Oct 28 '15 at 10:08
  • First do one thing in your code. Replace (etCurrent.getText().toString() == "")this condition with "(etCurrent.getText().toString().trim().equals("")) – Chirag Savsani Oct 28 '15 at 10:10
  • I did your suggestions but unfotunatelly not worked, by the way I found a link about "Backspace" problem. This looks like Android's general bug. http://stackoverflow.com/questions/18581636/android-cannot-capture-backspace-delete-press-in-soft-keyboard/19980975#19980975 – Colibri Oct 28 '15 at 10:21
0
    @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {


    if (keyCode == KeyEvent.KEYCODE_DEL) {
        if (mPineighthDigitEditText.getText().length() ==0 )
        {       //mPineighthDigitEditText.setText("");
            mPinseventthDigitEditText.requestFocus();
    }
          if (mPinseventthDigitEditText.getText().length() == 0){
           // mPinseventthDigitEditText.setText("");
            mPinsixthDigitEditText.requestFocus();}
          if (mPinsixthDigitEditText.getText().length() == 0) {
           // mPinsixthDigitEditText.setText("");
            mPinFifthDigitEditText.requestFocus();}
         if (mPinFifthDigitEditText.getText().length() == 0){
            //mPinFifthDigitEditText.setText("");
            mPinForthDigitEditText.requestFocus();}
         if (mPinForthDigitEditText.getText().length() == 0){
           // mPinForthDigitEditText.setText("");
            mPinThirdDigitEditText.requestFocus();}
          if (mPinThirdDigitEditText.getText().length() == 0){
            //mPinThirdDigitEditText.setText("");
          mPinSecondDigitEditText.requestFocus();}
         if (mPinSecondDigitEditText.getText().length() == 0){
            //mPinSecondDigitEditText.setText("");
            mPinFirstDigitEditText.requestFocus();}
          if (mPinFirstDigitEditText.getText().length() == 0 ) {
              mPinFirstDigitEditText.setText("");
          }
        return true;
    }

    return super.onKeyDown(keyCode, event);


}

}

IF More than one edit text filed's thank you :)

Gopal Reddy
  • 36
  • 1
  • 5
0

Writing this answer with an example of filling 4 editTexts for an OTP.

first create an array of 4 editTexts and bind them with the views

private var otpPins = arrayOfNulls<EditText>(4) //remember to input maxlenght = 1 in each view in xml file

otpPins[0] = findViewById(R.id.otp_1)
otpPins[1] = findViewById(R.id.otp_2)
otpPins[2] = findViewById(R.id.otp_3)
otpPins[3] = findViewById(R.id.otp_4)

Then add textWatcher so that the focus changes to next editText when any number is input

otpPins[0]?.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {

        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            if (s?.length ?: 0 >= 1) {
                otpPins[1]?.requestFocus()
            }
        }
    })

    otpPins[1]?.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {

        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            if (s?.length ?: 0 >= 1) {
                otpPins[2]?.requestFocus()
            }
        }
    })

    otpPins[2]?.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {

        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            if (s?.length ?: 0 >= 1) {
                otpPins[3]?.requestFocus()
            }
        }
    })

    otpPins[3]?.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {

        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            if (s?.length ?: 0 >= 1) {
                verifyOtpAndProceed()
            }
        }
    })

now create 1 inner class to detect backspace and change focus to previous editText

inner class PinOnKeyListener internal constructor(private val currentIndex: Int) :
    View.OnKeyListener {
    override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
        if (keyCode == KeyEvent.KEYCODE_DEL && event.action == KeyEvent.ACTION_DOWN) {
            if (otpPins[currentIndex]?.text.toString()
                    .isEmpty() && currentIndex != 0
            ) otpPins[currentIndex - 1]?.requestFocus()
        }
        return false
    }
}

Assign setOnKeyLister to each editText

otpPins[0]?.setOnKeyListener(PinOnKeyListener(0))
otpPins[1]?.setOnKeyListener(PinOnKeyListener(1))
otpPins[2]?.setOnKeyListener(PinOnKeyListener(2))
otpPins[3]?.setOnKeyListener(PinOnKeyListener(3))

The end result will be when you enter any number the focus will change to next pin. When backspace is pressed and if input is there, it will simply erase that and if no input is there it will move to previous pin.

mohit48
  • 712
  • 7
  • 9
-1

Simply use StringBuilder and state the editText you wanna focus on the backspace in here like below:

StringBuilder sb = new StringBuilder(); //define this inside addTextChangedListner 

public void afterTextChanged (Editable s) {
    if (sb.length() == 0) {
        previousEditText.requestFocus();
    }
}
Anh Pham
  • 2,108
  • 9
  • 18
  • 29
obhasha
  • 1
  • 2