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
- Timer shows in awkward format. I want only seconds.
- 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.