I am implementing a custom view for OTP of varying length upto 6 digits. I have extended a LinearLayout and use multiple edit text as its child view. Each edit text holds one digit. I want to implement the delete action from the soft keyboard for the above custom view. The following is the code for the OTP custom view.
public class OTPEditText extends LinearLayout {
private int mDigitSpacing = 8; // Space between digits
private int mDigitNumber = 6; // Number of digits
private int mDigitSize = 28; // Font size of the digits
private ArrayList<EditText> mEditTexts; // List of edit text each holding one digit
private OnCompleteListener mCompleteListener; //when all the edit text gets one digit each
public OTPEditText(Context context) {
super(context);
}
public OTPEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public OTPEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Add the required number of Edit Texts
* @param number - number of digits
*/
public void setDigitNumber(int number){
this.mDigitNumber = number;
addViews();
}
public void setOnCompleteListener(OnCompleteListener listener) {
this.mCompleteListener = listener;
}
private void addViews() {
removeAllViews();
mEditTexts = new ArrayList<>();
for(int i = 0; i < mDigitNumber; i++){
EditText editText = new EditText(getContext());
//Set the necessary attributes
editText.addTextChangedListener(new GenericTextWatcher(i));
mEditTexts.add(editText);
addView(editText);
}
requestLayout();
if(mEditTexts.size() > 0) {
mEditTexts.get(0).requestFocus();
}
}
/**
* similar to setText of an edit text, but
* set one digit each to the edit text
* @param s - string for the edit text
*/
public void setText(String s){
if(s.length() > mDigitNumber){
s = s.substring(0, mDigitNumber);
}
int i;
for(i = 0; i < s.length(); i++){
mEditTexts.get(i).setText(s.charAt(i));
}
for(; i < mEditTexts.size(); i++){
mEditTexts.get(i).setText("");
}
}
/**
* Similar to the getText of an edit text,
* concatenates the text from each edit text
* @return - concatenated string from each edit text
*/
public String getText() {
String text = "";
if(!Utils.isEmptyList(mEditTexts)) {
for (EditText editText : mEditTexts){
text += editText.getText().toString();
}
}
return text;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event){
return true;
}
/**
* Called whenever onClick of the View is called. Simulates the click event of
* the required edit text.
*/
public void doClick() {
if(!Utils.isEmptyList(mEditTexts)){
for(EditText editText : mEditTexts){
if(editText.getText().toString().equals("")){
editText.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN , 0, 0, 0));
editText.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_UP , 0, 0, 0));
return;
}
}
mEditTexts.get(mEditTexts.size()-1).dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN ,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mDigitSize,
getResources().getDisplayMetrics()), 0, 0));
mEditTexts.get(mEditTexts.size()-1).dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), MotionEvent.ACTION_UP ,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, mDigitSize,
getResources().getDisplayMetrics()), 0, 0));
}
}
public interface OnCompleteListener {
void onComplete();
}
// Generic edit text watcher
public class GenericTextWatcher implements TextWatcher {
private int index;
public GenericTextWatcher(int index){
this.index = index;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if(s.toString().length() >= 1){
if(index +1 < mEditTexts.size()){
mEditTexts.get(index + 1).requestFocus();
} else if(index == mEditTexts.size() - 1 && mCompleteListener != null){
mCompleteListener.onComplete();
}
}
}
}
}