Home > other >  How to show countdown timer
How to show countdown timer

Time:10-28

I want a OTP SCREEN. I succeeded in creating OTP screen. Below that I want a resend otp button and 1 timer. If no input, the timer should start while the button is not in focus. As soon as otp is entered, the timer should stop. I have a timer function, start timer that I am calling from onCreate end of activity. It should unfocus the send button and when expires, should bring that to focus. But the timer is not displaying on screen and button is displayed after some time.

I want

  1. Timer shows in awkward format. I want only seconds.
  2. the button is invisible now, it should be visible but dimmed that is out of focus

CODE:

           public class OTPActivity extends AppCompatActivity implements  AdapterView.OnItemSelectedListener{
    private EditText editText1, editText2, editText3, editText4;
    private EditText[] editTexts;
    CountDownTimer cTimer = null;
    TextView tv;
    Button resend;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_otpactivity2);

        tv = (TextView) findViewById(R.id.timer);
        resend = (Button) findViewById(R.id.ResendOTP);
        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));
        startTimer();
        resend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startTimer();
            }
        });
    }
    void startTimer() {
        resend.setEnabled(false);

        cTimer = new CountDownTimer(30000, 1000) {
            public void onTick(long millisUntilFinished) {
                tv.setText("seconds remaining: "  String.valueOf(millisUntilFinished/1000));

            }
            public void onFinish() {
                tv.setText("Re send OTP!");
                resend.setEnabled(true);
            }
        };
        cTimer.start();
    }


    //cancel timer
    void cancelTimer() {
        if(cTimer!=null)
            cTimer.cancel();
    }
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }

    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;
        }

    }
}

xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="match_parent"
    >
    <androidx.cardview.widget.CardView
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:id="@ id/card_view"
        android:layout_width="180dp"
        card_view:cardElevation="4dp"
        android:gravity="center"
        android:layout_height="60dp"
        card_view:cardCornerRadius="4dp">
        <LinearLayout

            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_gravity="center">
        <EditText
            android:id="@ id/otpEdit1"
            android:digits="1234567890"
            android:inputType="number"
            android:maxLength="1"
            android:gravity="center"
            android:layout_weight="1"
            android:layout_width="2dp"
            android:layout_height="wrap_content"
            />
        <EditText
            android:id="@ id/otpEdit2"
            android:digits="1234567890"
            android:inputType="number"
            android:maxLength="1"
            android:gravity="center"
            android:layout_weight="1"
            android:layout_width="2dp"
            android:layout_height="wrap_content"
        />
        <EditText
            android:id="@ id/otpEdit3"
            android:digits="1234567890"
            android:inputType="number"
            android:maxLength="1"
            android:gravity="center"
            android:layout_weight="1"
            android:layout_width="2dp"
            android:layout_height="wrap_content"
        />
        <EditText
            android:id="@ id/otpEdit4"
            android:digits="1234567890"
            android:inputType="number"
            android:maxLength="1"
            android:gravity="center"
            android:layout_weight="1"
            android:layout_width="2dp"
            android:layout_height="wrap_content"
        />
        </LinearLayout>
    </androidx.cardview.widget.CardView>
    <TextView
        android:id="@ id/timer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Timer"
        android:layout_marginLeft="10dp"/>
    <Button
        android:id="@ id/ResendOTP"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ResendOTP" />
</LinearLayout>

CodePudding user response:

onTick method calls after 1 second as per your countdowntimer setup.Because of that button is visible at starting of activity.

Also if you want to show seconds only in countdown timer then use following syntax :

void startTimer() {
    tv = (TextView) findViewById(R.id.timer);
    cTimer = new CountDownTimer(30000, 1000) {
        public void onTick(long millisUntilFinished) {
            tv.setText("seconds remaining: "  String.valueOf(millisUntilFinished/1000));
        }
        public void onFinish() {
            tv.setText("Re send OTP!");
            resend.setEnabled(true);
        }
    };
    cTimer.start();
}

You don;t need to invisible button on each tick it will increase ui events. You need to set invisible the button in onCreate method or anywhere before starting timer like this:

            resend.setVisibility(View.INVISIBLE);
            startTimer();

Also for dimming purpose you need to change the Button color and use setEnabled method for enabling and disabling button click.

CodePudding user response:

You should be using setEnabled on the button instead on setting visibility.

Instead of disabling button in onTick which will be called everytime, you can set it once in your startTimer function. Just update your TextView in onTick. You can also set these initial values in your XML if you want.

Since you want to display seconds, instead of new SimpleDateFormat("mm:ss:SS").format(new Date( millisUntilFinished)) you can simply do millisUntilFinished / 1000 and set it to your TextView.

  • Related