Custom phone number format (XXX-XXX-XXXX) TextWatcher getting stuck - android

Things is Working:
The format (XXX-XXX-XXXX) which I want in phone number EditText is worked.
Problem is:
While deleting character "-" ,It can't deleted. I am getting stuck.
PhoneNumberTextWatcher.java
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
public class PhoneNumberTextWatcher implements TextWatcher {
private static final String TAG = PhoneNumberTextWatcher.class
.getSimpleName();
private EditText edTxt;
public boolean isDelete;
public PhoneNumberTextWatcher(EditText edTxtPhone) {
this.edTxt = edTxtPhone;
edTxt.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.KEYCODE_DEL) {
isDelete = true;
LogUtils.Log_e("ISDELETE", String.valueOf(isDelete));
}
return false;
}
});
}
l.substring(6, val.length());
} else if (val.length() > 3 && val.length() < 6) {
b = val.substring(3, val.length());
}
StringBuffer stringBuffer = new StringBuffer();
if (a != null && a.length() > 0) {
stringBuffer.append(a);
if (a.length() == 3) {
stringBuffer.append("-");
}
}
if (b != null && b.length() > 0) {
stringBuffer.append(b);
if (b.length() == 3) {
stringBuffer.append("-");
}
}
if (c != null && c.length() > 0) {
stringBuffer.append(c);
}
edTxt.removeTextChangedListener(this);
edTxt.setText(stringBuffer.toString());
edTxt.setSelection(edTxt.getText().toString().length());
edTxt.addTextChangedListener(this);
} else {
edTxt.removeTextChangedListener(this);
edTxt.setText("");
edTxt.addTextChangedListener(this);
}
}
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(Editable s) {
LogUtils.Log_e("ISDELETE", String.valueOf(isDelete));
if (isDelete) {
isDelete = false;
return;
}
LogUtils.Log_e("ISDELETE", String.valueOf(isDelete));
String val = s.toString();
String a = "";
String b = "";
String c = "";
if (val != null && val.length() > 0) {
val = val.replace("-", "");
if (val.length() >= 3) {
a = val.substring(0, 3);
} else if (val.length() < 3) {
a = val.substring(0, val.length());
}
if (val.length() >= 6) {
b = val.substring(3, 6);
c = val.substring(6, val.length());
} else if (val.length() > 3 && val.length() < 6) {
b = val.substring(3, val.length());
}
StringBuffer stringBuffer = new StringBuffer();
if (a != null && a.length() > 0) {
stringBuffer.append(a);
if (a.length() == 3) {
stringBuffer.append("-");
}
}
if (b != null && b.length() > 0) {
stringBuffer.append(b);
if (b.length() == 3) {
stringBuffer.append("-");
}
}
if (c != null && c.length() > 0) {
stringBuffer.append(c);
}
edTxt.removeTextChangedListener(this);
edTxt.setText(stringBuffer.toString());
edTxt.setSelection(edTxt.getText().toString().length());
edTxt.addTextChangedListener(this);
} else {
edTxt.removeTextChangedListener(this);
edTxt.setText("");
edTxt.addTextChangedListener(this);
}
}
}
I am trying TextWatcher using below code:
edtOrderCardPhone.addTextChangedListener(new PhoneNumberTextWatcher(edtOrderCardPhone));
See related question here.
Can any one help to solve problem!

I found solution to change my PhoneNumberTextWatcher using below code.
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
public class PhoneNumberTextWatcher implements TextWatcher {
private static final String TAG = "PhoneNumberTextWatcher";
private EditText editText;
public PhoneNumberTextWatcher(EditText edTxtPhone) {
this.editText = edTxtPhone;
}
public void onTextChanged(CharSequence s, int cursorPosition, int before,
int count) {
if (before == 0 && count == 1) { //Entering values
String val = s.toString();
String a = "";
String b = "";
String c = "";
if (val != null && val.length() > 0) {
val = val.replace("-", "");
if (val.length() >= 3) {
a = val.substring(0, 3);
} else if (val.length() < 3) {
a = val.substring(0, val.length());
}
if (val.length() >= 6) {
b = val.substring(3, 6);
c = val.substring(6, val.length());
} else if (val.length() > 3 && val.length() < 6) {
b = val.substring(3, val.length());
}
StringBuffer stringBuffer = new StringBuffer();
if (a != null && a.length() > 0) {
stringBuffer.append(a);
}
if (b != null && b.length() > 0) {
stringBuffer.append("-");
stringBuffer.append(b);
}
if (c != null && c.length() > 0) {
stringBuffer.append("-");
stringBuffer.append(c);
}
editText.removeTextChangedListener(this);
editText.setText(stringBuffer.toString());
if (cursorPosition == 3 || cursorPosition == 7) {
cursorPosition = cursorPosition + 2;
} else {
cursorPosition = cursorPosition + 1;
}
if (cursorPosition <= editText.getText().toString().length()) {
editText.setSelection(cursorPosition);
} else {
editText.setSelection(editText.getText().toString().length());
}
editText.addTextChangedListener(this);
} else {
editText.removeTextChangedListener(this);
editText.setText("");
editText.addTextChangedListener(this);
}
}
if (before == 1 && count == 0) { //Deleting values
String val = s.toString();
String a = "";
String b = "";
String c = "";
if (val != null && val.length() > 0) {
val = val.replace("-", "");
if (cursorPosition == 3) {
val = removeCharAt(val, cursorPosition - 1, s.toString().length() - 1);
} else if (cursorPosition == 7) {
val = removeCharAt(val, cursorPosition - 2, s.toString().length() - 2);
}
if (val.length() >= 3) {
a = val.substring(0, 3);
} else if (val.length() < 3) {
a = val.substring(0, val.length());
}
if (val.length() >= 6) {
b = val.substring(3, 6);
c = val.substring(6, val.length());
} else if (val.length() > 3 && val.length() < 6) {
b = val.substring(3, val.length());
}
StringBuffer stringBuffer = new StringBuffer();
if (a != null && a.length() > 0) {
stringBuffer.append(a);
}
if (b != null && b.length() > 0) {
stringBuffer.append("-");
stringBuffer.append(b);
}
if (c != null && c.length() > 0) {
stringBuffer.append("-");
stringBuffer.append(c);
}
editText.removeTextChangedListener(this);
editText.setText(stringBuffer.toString());
if (cursorPosition == 3 || cursorPosition == 7) {
cursorPosition = cursorPosition - 1;
}
if (cursorPosition <= editText.getText().toString().length()) {
editText.setSelection(cursorPosition);
} else {
editText.setSelection(editText.getText().toString().length());
}
editText.addTextChangedListener(this);
} else {
editText.removeTextChangedListener(this);
editText.setText("");
editText.addTextChangedListener(this);
}
}
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(Editable s) {
}
public static String removeCharAt(String s, int pos, int length) {
String value = "";
if (length > pos) {
value = s.substring(pos + 1);
}
return s.substring(0, pos) + value;
}
}
Thanks B Bhanu Chander for solution.

You can do this way:
private EditText editText;
onCreate():
editText = (EditText) findViewById(R.id.editText);
editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
Screen shot:
Hope this will help you.

Related

Masked EditText with format (XXX) XXX-XXXX ext.XXXXXX in android?

How can I mask EditText with below format in android ?
(XXX) XXX-XXXX ext.XXXXXX i.e (654) 321-5846 ext.654321
Used below Custom Edit Text class
package com.test.PhoneNumberFormatter;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
import com.test.R;
import static android.content.ContentValues.TAG;
public class MaskedEditText extends AppCompatEditText implements TextWatcher {
public static final String SPACE = " ";
private String mask;
private char charRepresentation;
private boolean keepHint;
private int[] rawToMask;
private RawText rawText;
private boolean editingBefore;
private boolean editingOnChanged;
private boolean editingAfter;
private int[] maskToRaw;
private int selection;
private boolean initialized;
private boolean ignore;
protected int maxRawLength;
private int lastValidMaskPosition;
private boolean selectionChanged;
private OnFocusChangeListener focusChangeListener;
private String allowedChars;
private String deniedChars;
public MaskedEditText(Context context) {
super(context);
init();
}
public MaskedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.MaskedEditText);
mask = attributes.getString(R.styleable.MaskedEditText_mask);
allowedChars = attributes.getString(R.styleable.MaskedEditText_allowed_chars);
deniedChars = attributes.getString(R.styleable.MaskedEditText_denied_chars);
String representation = attributes.getString(R.styleable.MaskedEditText_char_representation);
if (representation == null) {
charRepresentation = '#';
} else {
charRepresentation = representation.charAt(0);
}
keepHint = attributes.getBoolean(R.styleable.MaskedEditText_keep_hint, false);
cleanUp();
// Ignoring enter key presses
setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
switch (actionId) {
// case EditorInfo.IME_ACTION_NEXT:
// fixing actionNext
// return false;
default:
return true;
}
}
});
attributes.recycle();
}
#Override
public Parcelable onSaveInstanceState() {
final Parcelable superParcellable = super.onSaveInstanceState();
final Bundle state = new Bundle();
state.putParcelable("super", superParcellable);
state.putString("text", getRawText());
state.putBoolean("keepHint", isKeepHint());
return state;
}
#Override
public void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
keepHint = bundle.getBoolean("keepHint", false);
super.onRestoreInstanceState(((Bundle) state).getParcelable("super"));
final String text = bundle.getString("text");
setText(text);
Log.d(TAG, "onRestoreInstanceState: " + text);
}
#Override
public void setText(CharSequence text, BufferType type) {
// if (text == null || text.equals("")) return;
super.setText(text, type);
}
/**
* #param listener - its onFocusChange() method will be called before performing MaskedEditText operations,
* related to this event.
*/
#Override
public void setOnFocusChangeListener(OnFocusChangeListener listener) {
focusChangeListener = listener;
}
private void cleanUp() {
initialized = false;
generatePositionArrays();
rawText = new RawText();
selection = rawToMask[0];
editingBefore = true;
editingOnChanged = true;
editingAfter = true;
if (hasHint() && rawText.length() == 0) {
this.setText(makeMaskedTextWithHint());
} else {
this.setText(makeMaskedText());
}
editingBefore = false;
editingOnChanged = false;
editingAfter = false;
maxRawLength = maskToRaw[previousValidPosition(mask.length() - 1)] + 1;
lastValidMaskPosition = findLastValidMaskPosition();
initialized = true;
super.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (focusChangeListener != null) {
focusChangeListener.onFocusChange(v, hasFocus);
}
if (hasFocus()) {
selectionChanged = false;
MaskedEditText.this.setSelection(lastValidPosition());
}
}
});
}
private int findLastValidMaskPosition() {
for (int i = maskToRaw.length - 1; i >= 0; i--) {
if (maskToRaw[i] != -1) return i;
}
throw new RuntimeException("Mask must contain at least one representation char");
}
private boolean hasHint() {
return getHint() != null;
}
public MaskedEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setMask(String mask) {
this.mask = mask;
cleanUp();
}
public String getMask() {
return this.mask;
}
public String getRawText() {
return this.rawText.getText();
}
public void setCharRepresentation(char charRepresentation) {
this.charRepresentation = charRepresentation;
cleanUp();
}
public char getCharRepresentation() {
return this.charRepresentation;
}
/**
* Generates positions for values characters. For instance:
* Input data: mask = "+7(###)###-##-##
* After method execution:
* rawToMask = [3, 4, 5, 6, 8, 9, 11, 12, 14, 15]
* maskToRaw = [-1, -1, -1, 0, 1, 2, -1, 3, 4, 5, -1, 6, 7, -1, 8, 9]
* charsInMask = "+7()- " (and space, yes)
*/
private void generatePositionArrays() {
int[] aux = new int[mask.length()];
maskToRaw = new int[mask.length()];
String charsInMaskAux = "";
int charIndex = 0;
for (int i = 0; i < mask.length(); i++) {
char currentChar = mask.charAt(i);
if (currentChar == charRepresentation) {
aux[charIndex] = i;
maskToRaw[i] = charIndex++;
} else {
String charAsString = Character.toString(currentChar);
if (!charsInMaskAux.contains(charAsString)) {
charsInMaskAux = charsInMaskAux.concat(charAsString);
}
maskToRaw[i] = -1;
}
}
if (charsInMaskAux.indexOf(' ') < 0) {
charsInMaskAux = charsInMaskAux + SPACE;
}
char[] charsInMask = charsInMaskAux.toCharArray();
rawToMask = new int[charIndex];
for (int i = 0; i < charIndex; i++) {
rawToMask[i] = aux[i];
}
}
private void init() {
addTextChangedListener(this);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
if (!editingBefore) {
editingBefore = true;
if (start > lastValidMaskPosition) {
ignore = true;
}
int rangeStart = start;
if (after == 0) {
rangeStart = erasingStart(start);
}
Range range = calculateRange(rangeStart, start + count);
if (range.getStart() != -1) {
rawText.subtractFromString(range);
}
if (count > 0) {
selection = previousValidPosition(start);
}
}
}
private int erasingStart(int start) {
while (start > 0 && maskToRaw[start] == -1) {
start--;
}
return start;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!editingOnChanged && editingBefore) {
editingOnChanged = true;
if (ignore) {
return;
}
if (count > 0) {
int startingPosition = maskToRaw[nextValidPosition(start)];
String addedString = s.subSequence(start, start + count).toString();
count = rawText.addToString(clear(addedString), startingPosition, maxRawLength);
if (initialized) {
int currentPosition;
if (startingPosition + count < rawToMask.length)
currentPosition = rawToMask[startingPosition + count];
else
currentPosition = lastValidMaskPosition + 1;
selection = nextValidPosition(currentPosition);
}
}
}
}
#Override
public void afterTextChanged(Editable s) {
if (!editingAfter && editingBefore && editingOnChanged) {
editingAfter = true;
if (hasHint() && (keepHint || rawText.length() == 0)) {
setText(makeMaskedTextWithHint());
} else {
setText(makeMaskedText());
}
selectionChanged = false;
setSelection(selection);
editingBefore = false;
editingOnChanged = false;
editingAfter = false;
ignore = false;
}
}
public boolean isKeepHint() {
return keepHint;
}
public void setKeepHint(boolean keepHint) {
this.keepHint = keepHint;
setText(getRawText());
}
#Override
protected void onSelectionChanged(int selStart, int selEnd) {
// On Android 4+ this method is being called more than 1 time if there is a hint in the EditText, what moves the cursor to left
// Using the boolean var selectionChanged to limit to one execution
if (initialized) {
if (!selectionChanged) {
selStart = fixSelection(selStart);
selEnd = fixSelection(selEnd);
// exactly in this order. If getText.length() == 0 then selStart will be -1
if (selStart > getText().length()) selStart = getText().length();
if (selStart < 0) selStart = 0;
// exactly in this order. If getText.length() == 0 then selEnd will be -1
if (selEnd > getText().length()) selEnd = getText().length();
if (selEnd < 0) selEnd = 0;
setSelection(selStart, selEnd);
selectionChanged = true;
} else {
//check to see if the current selection is outside the already entered text
if (selStart > rawText.length() - 1) {
final int start = fixSelection(selStart);
final int end = fixSelection(selEnd);
if (start >= 0 && end < getText().length()) {
setSelection(start, end);
}
}
}
}
super.onSelectionChanged(selStart, selEnd);
}
private int fixSelection(int selection) {
if (selection > lastValidPosition()) {
return lastValidPosition();
} else {
return nextValidPosition(selection);
}
}
private int nextValidPosition(int currentPosition) {
while (currentPosition < lastValidMaskPosition && maskToRaw[currentPosition] == -1) {
currentPosition++;
}
if (currentPosition > lastValidMaskPosition) return lastValidMaskPosition + 1;
return currentPosition;
}
private int previousValidPosition(int currentPosition) {
while (currentPosition >= 0 && maskToRaw[currentPosition] == -1) {
currentPosition--;
if (currentPosition < 0) {
return nextValidPosition(0);
}
}
return currentPosition;
}
private int lastValidPosition() {
if (rawText.length() == maxRawLength) {
return rawToMask[rawText.length() - 1] + 1;
}
return nextValidPosition(rawToMask[rawText.length()]);
}
private String makeMaskedText() {
int maskedTextLength;
if (rawText.length() < rawToMask.length) {
maskedTextLength = rawToMask[rawText.length()];
} else {
maskedTextLength = mask.length();
}
char[] maskedText = new char[maskedTextLength]; //mask.replace(charRepresentation, ' ').toCharArray();
for (int i = 0; i < maskedText.length; i++) {
int rawIndex = maskToRaw[i];
if (rawIndex == -1) {
maskedText[i] = mask.charAt(i);
} else {
maskedText[i] = rawText.charAt(rawIndex);
}
}
return new String(maskedText);
}
private CharSequence makeMaskedTextWithHint() {
SpannableStringBuilder ssb = new SpannableStringBuilder();
int mtrv;
int maskFirstChunkEnd = rawToMask[0];
for (int i = 0; i < mask.length(); i++) {
mtrv = maskToRaw[i];
if (mtrv != -1) {
if (mtrv < rawText.length()) {
ssb.append(rawText.charAt(mtrv));
} else {
ssb.append(getHint().charAt(maskToRaw[i]));
}
} else {
ssb.append(mask.charAt(i));
}
if ((keepHint && rawText.length() < rawToMask.length && i >= rawToMask[rawText.length()])
|| (!keepHint && i >= maskFirstChunkEnd)) {
ssb.setSpan(new ForegroundColorSpan(getCurrentHintTextColor()), i, i + 1, 0);
}
}
return ssb;
}
private Range calculateRange(int start, int end) {
Range range = new Range();
for (int i = start; i <= end && i < mask.length(); i++) {
if (maskToRaw[i] != -1) {
if (range.getStart() == -1) {
range.setStart(maskToRaw[i]);
}
range.setEnd(maskToRaw[i]);
}
}
if (end == mask.length()) {
range.setEnd(rawText.length());
}
if (range.getStart() == range.getEnd() && start < end) {
int newStart = previousValidPosition(range.getStart() - 1);
if (newStart < range.getStart()) {
range.setStart(newStart);
}
}
return range;
}
private String clear(String string) {
if (deniedChars != null) {
for (char c : deniedChars.toCharArray()) {
string = string.replace(Character.toString(c), "");
}
}
if (allowedChars != null) {
StringBuilder builder = new StringBuilder(string.length());
for (char c : string.toCharArray()) {
if (allowedChars.contains(String.valueOf(c))) {
builder.append(c);
}
}
string = builder.toString();
}
return string;
}
}
In activity_main.xml
<com.test.PhoneNumberFormatter.MaskedEditText
android:id="#+id/phone_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:hint="#string/phone_number"
android:imeOptions="actionNext"
android:inputType="textPhonetic"
android:paddingBottom="#dimen/_3sdp"
android:paddingTop="#dimen/_8sdp"
android:textColorHint="#color/grey_color"
android:textSize="#dimen/_12sdp"
mask:allowed_chars="1234567890ext."
mask:keep_hint="false"
mask:mask="(###)###-#### ext.######" />
Thanks.
For format Edit-text, below things can be helpful to you.
**Step 1** : Add following line in your build.gradle file
implementation 'com.github.pinball83:masked-edittext:1.0.4'
**Step 2 :** by xml :
<com.github.pinball83.maskededittext.MaskedEditText
android:id="#+id/masked_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
app:mask="8 (***) *** **-**"
app:notMaskedSymbol="*"
app:maskIcon="#drawable/abc_ic_clear_mtrl_alpha"
app:maskIconColor="#color/colorPrimary"
/>
or by java file :
MaskedEditText maskedEditText = new MaskedEditText.Builder(context)
.mask("8 (***) *** **-**")
.notMaskedSymbol("*")
.icon(R.drawable.ic_account_circle)
.iconCallback(unmaskedText -> { //Icon click callback handler })
.build();
MaskedEditText editText = new MaskedEditText.Builder(context)
.mask("8 (***) *** **-**")
.notMaskedSymbol("*")
.build();; //set mask to "8 (***) *** **-**" and not masked symbol to "*"
Text setup and formatting
MaskedEditText editText = new MaskedEditText..Builder(context)
.mask("8 (***) *** **-**")
.notMaskedSymbol("*")
.format("[1][2][3] [4][5][6]-[7][8]-[10][9]")//set format of returned data input into MaskedEditText
.build();
editText.setMaskedText("5551235567");
for more details use following url :
https://github.com/pinball83/Masked-Edittext
Enjoy :)
Step 1 : Create editText
<EditText
android:id="#+id/masked_edit_text"
android:layout_width="yourSize"
android:layout_height="yourSize"
android:inputType="textPassword"/>
Step2:
public class CustomTransformation extends PasswordTransformationMethod {
#Override
public CharSequence getTransformation(CharSequence source, View view) {
return new TransformedSequence(source);
}
private class TransformedSequence implements CharSequence {
private CharSequence sequence;
public TransformedSequence(CharSequence source) {
sequence = source; // Store char sequence
}
public char charAt(int index) {
return 'X'; // Replace with what you want.
}
public int length() {
return sequence.length(); // return the length
}
public CharSequence subSequence(int start, int end) {
return sequence.subSequence(start, end); //return sequence
}
}
Step 3: apply the transformation
EditText edittext = findViewById(R.id.masked_edit_text);
edittext.setTransformationMethod(new CustomTransformation());
https://github.com/mukeshsolanki/country-picker-android
try this library .
this will automatically mask your edittext with selected country number .

replacing comma symbol with a pipe symbol in Comma Tokenizer android not working

I am using Comma Tokenizer in MultiAutoCompleteTextView but I want a pipe symbol after each selected text instead of a comma. As on stack I tried replacing the symbol in the base class but its not working. pls let me know if I am doing something wrong
public static class CommaTokenizer implements Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != '|') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == '|') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == '|') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + "| ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + "| ";
}
}
}
Try this
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.widget.MultiAutoCompleteTextView;
/**
* Created by nilesh on 21/3/18.
*/
public class MyTokenizer implements MultiAutoCompleteTextView.Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != ' ') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + "|");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + "| ";
}
}
}
}
ACTIVITY CODE
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.InputType;
import android.widget.ArrayAdapter;
import android.widget.MultiAutoCompleteTextView;
public class MainActivity extends AppCompatActivity {
MultiAutoCompleteTextView multiAutoCompleteTextView;
String []myArray;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myArray=getResources().getStringArray(R.array.spinner_array);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line, myArray);
multiAutoCompleteTextView = findViewById(R.id.mMultiAutoCompleteTextView);
multiAutoCompleteTextView.setTokenizer(new MyTokenizer());
multiAutoCompleteTextView.setAdapter(adapter);
multiAutoCompleteTextView.setTokenizer(new MyTokenizer());
multiAutoCompleteTextView.setInputType(InputType.TYPE_CLASS_TEXT);
multiAutoCompleteTextView.setThreshold(1);
}
}

converting numbers to currency format when text changes

I am using RxTextView.textChanges for EditText that when the user is typing change value of EditText to convert numbers to currency format like below:
1,000
But I can't see any convert numbers to currency format.
I am using from: NumberFormat.getNumberInstance(Locale.US).format(productPrice);
My code is like bellow:
Observable<CharSequence> observableDiscountPrice = RxTextView.textChanges(discountPriceEdittext);
observableDiscountPrice.map(new Function<CharSequence, Boolean>() {
#Override
public Boolean apply(#io.reactivex.annotations.NonNull CharSequence charSequence) throws Exception {
try {
if (charSequence.length() > 0) {
String pPrice = NumberFormat.getNumberInstance(Locale.US).format(charSequence.toString());
originalPriceEdittext.setText(String.valueOf(pPrice));
return true;
} else {
return false;
}
} catch (Exception e) {
return true;
}
}
}).subscribe(new Subject<Boolean>() {
#Override
public boolean hasObservers() {
return false;
}
#Override
public boolean hasThrowable() {
return false;
}
#Override
public boolean hasComplete() {
return false;
}
#Override
public Throwable getThrowable() {
return null;
}
#Override
protected void subscribeActual(Observer<? super Boolean> observer) {
}
#Override
public void onSubscribe(#io.reactivex.annotations.NonNull Disposable d) {
}
#Override
public void onNext(#io.reactivex.annotations.NonNull Boolean aBoolean) {
}
#Override
public void onError(#io.reactivex.annotations.NonNull Throwable e) {
}
#Override
public void onComplete() {
}
});
Use this TextWatcher class:
public class NumberTextWatcherWithSeperator implements TextWatcher {
private EditText editText;
public NumberTextWatcherWithSeperator(EditText editText) {
this.editText = editText;
}
#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) {
try {
editText.removeTextChangedListener(this);
String value = editText.getText().toString();
if (!value.equals("")) {
if (value.startsWith(".")) {
editText.setText("0.");
}
if (value.startsWith("0") && !value.startsWith("0.")) {
editText.setText("");
}
String str = editText.getText().toString().replaceAll(",", "");
if (!value.equals(""))
editText.setText(getDecimalFormattedString(str));
editText.setSelection(editText.getText().toString().length());
}
editText.addTextChangedListener(this);
} catch (Exception ex) {
ex.printStackTrace();
editText.addTextChangedListener(this);
}
}
private static String getDecimalFormattedString(String value) {
StringTokenizer lst = new StringTokenizer(value, ".");
String str1 = value;
String str2 = "";
if (lst.countTokens() > 1) {
str1 = lst.nextToken();
str2 = lst.nextToken();
}
String str3 = "";
int i = 0;
int j = -1 + str1.length();
if (str1.charAt(-1 + str1.length()) == '.') {
j--;
str3 = ".";
}
for (int k = j; ; k--) {
if (k < 0) {
if (str2.length() > 0)
str3 = str3 + "." + str2;
return str3;
}
if (i == 3) {
str3 = "," + str3;
i = 0;
}
str3 = str1.charAt(k) + str3;
i++;
}
}
}
and
yourEditText.addTextChangedListener(new NumberTextWatcherWithSeperator(yourEditText));
Take a look at https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
DecimalFormat myFormatter = new DecimalFormat("###,###.###");
String output = myFormatter.format(156456.673);
System.out.println(156456.673 + " " + "###,###.###" + " " + output);
// I/System.out: 156456.673 ###,###.### 156,456.673
I'm using this watcher to do the same thing:
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;
public class CurrencyTextWatcher implements TextWatcher {
private EditText ed;
private String lastText;
private boolean bDel = false;
private boolean bInsert = false;
private int pos;
public CurrencyTextWatcher(EditText ed) {
this.ed = ed;
}
public static String getStringWithSeparator(long value) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(Locale.US);
String f = formatter.format(value);
return f;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
bDel = false;
bInsert = false;
if (before == 1 && count == 0) {
bDel = true;
pos = start;
} else if (before == 0 && count == 1) {
bInsert = true;
pos = start;
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
lastText = s.toString();
}
#Override
public void afterTextChanged(Editable s) {
ed.removeTextChangedListener(this);
StringBuilder sb = new StringBuilder();
String text = s.toString();
for (int i = 0; i < text.length(); i++) {
if ((text.charAt(i) >= 0x30 && text.charAt(i) <= 0x39) || text.charAt(i) == '.' || text.charAt(i) == ',')
sb.append(text.charAt(i));
}
if (!sb.toString().equals(s.toString())) {
bDel = bInsert = false;
}
String newText = getFormattedString(sb.toString());
s.clear();
s.append(newText);
ed.addTextChangedListener(this);
if (bDel) {
int idx = pos;
if (lastText.length() - 1 > newText.length())
idx--;
if (idx < 0)
idx = 0;
ed.setSelection(idx);
} else if (bInsert) {
int idx = pos + 1;
if (lastText.length() + 1 < newText.length())
idx++;
if (idx > newText.length())
idx = newText.length();
ed.setSelection(idx);
}
}
private String getFormattedString(String text) {
String res = "";
try {
String temp = text.replace(",", "");
long part1;
String part2 = "";
int dotIndex = temp.indexOf(".");
if (dotIndex >= 0) {
part1 = Long.parseLong(temp.substring(0, dotIndex));
if (dotIndex + 1 <= temp.length()) {
part2 = temp.substring(dotIndex + 1).trim().replace(".", "").replace(",", "");
}
} else
part1 = Long.parseLong(temp);
res = getStringWithSeparator(part1);
if (part2.length() > 0)
res += "." + part2;
else if (dotIndex >= 0)
res += ".";
} catch (Exception ex) {
ex.printStackTrace();
}
return res;
}
}
In case you want to and a dollar sign
fun multiply_two_numbers() {
val x = etValOne.text.toString()
val y = etValTwo.text.toString()
val c = x.toDouble().times(y.toDouble())
//val c = (x.toDouble() * y.toDouble())
val df = DecimalFormat("$ "+"0.00")
df.roundingMode = RoundingMode.CEILING
df.format(c)
etANS.setText(df.format(c))
}

Issue while removing automatically added characters to custom PhoneNumberTextWatcher (XXX) XXX-XXXX

My code is working fine when formatting text in (XXX) XXX-XXXX format. But when removing characters, it stops once reached to character -/(). If I again put cursor to any number characters -/() will automatically get removed.
Here is code I used.
public class PhoneNumberTextWatcher implements TextWatcher {
private static final String TAG = PhoneNumberTextWatcher.class
.getSimpleName();
private EditText edTxt;
private boolean isDelete;
public PhoneNumberTextWatcher(EditText edTxtPhone) {
this.edTxt = edTxtPhone;
edTxt.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
isDelete = true;
}
return false;
}
});
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(Editable s) {
if (isDelete) {
isDelete = false;
return;
}
String val = s.toString();
String a = "";
String b = "";
String c = "";
if (val != null && val.length() > 0) {
val = val.replace("-", "");
val = val.replace("(", "");
val = val.replace(" ", "");
val = val.replace(")", "");
if (val.length() >= 3) {
a = val.substring(0, 3);
} else if (val.length() < 3) {
a = val.substring(0, val.length());
}
if (val.length() >= 6) {
b = val.substring(3, 6);
c = val.substring(6, val.length());
} else if (val.length() > 3 && val.length() < 6) {
b = val.substring(3, val.length());
}
StringBuffer stringBuffer = new StringBuffer();
if (a != null && a.length() > 0) {
if (a.length() == 3) {
stringBuffer.append("("+a+")"+" ");
}
else{
stringBuffer.append(a);
}
}
if (b != null && b.length() > 0) {
stringBuffer.append(b);
if (b.length() == 3) {
stringBuffer.append("-");
}
}
if (c != null && c.length() > 0) {
stringBuffer.append(c);
}
edTxt.removeTextChangedListener(this);
edTxt.setText(stringBuffer.toString());
edTxt.setSelection(edTxt.getText().toString().length());
edTxt.addTextChangedListener(this);
} else {
edTxt.removeTextChangedListener(this);
edTxt.setText("");
edTxt.addTextChangedListener(this);
}
}
}
No need to listen for Delete key. Just store the previous value of edittext and compare it with new when afterTextChanged is called. Code below works great in my project. I have modified it for (XXX) XXX-XXXX format. You can modify the logic to specify when to delete special characters (, ) and -.
PhoneNumberTextWatcher:
public class PhoneNumberTextWatcher implements TextWatcher {
private EditText phoneNumberEditText;
private String phoneNumber = "";
public PhoneNumberTextWatcher(EditText editText) {
phoneNumberEditText = editText;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void afterTextChanged(Editable s) {
String newValue = s.toString();
if (newValue.length() > phoneNumber.length()) {
phoneNumber = s.toString();
if (phoneNumber.length() == 4) {
if ('(' != phoneNumber.charAt(0)) {
phoneNumberEditText.setText("(" + phoneNumber.substring(0, phoneNumber.length() - 1) + ") " + phoneNumber.substring(phoneNumber.length() - 1));
phoneNumberEditText.setSelection(phoneNumber.length());
}
} else if (phoneNumber.length() == 10) {
phoneNumberEditText.setText(phoneNumber.substring(0, phoneNumber.length() - 1) + "-" + phoneNumber.substring(phoneNumber.length() - 1));
phoneNumberEditText.setSelection(phoneNumber.length());
}
}
else if (newValue.length() < phoneNumber.length()) {
phoneNumber = s.toString();
if (phoneNumber.length() == 10) {
phoneNumberEditText.setText(phoneNumber.substring(0, phoneNumber.length() - 1));
phoneNumberEditText.setSelection(phoneNumber.length());
}
else if (phoneNumber.length() == 6) {
phoneNumberEditText.setText(phoneNumber.substring(1, phoneNumber.length() - 2));
phoneNumberEditText.setSelection(phoneNumber.length());
}
}
}
}

I want to pop up a drop down list on press of #.

i am new to android and trying to make a tagging feature in which when i type # a drop down list will be shown(not after writing letter after #).. I read the similar type of question here but i did not get the answer.. Please help me with this problem .
MultiAutoCompleteTextView mt=(MultiAutoCompleteTextView)
findViewById(R.id.multiAutoCompleteTextView1);
mt.setTokenizer(new AtTokenizer());
ArrayAdapter<String> adp=new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line,str);
mt.setThreshold(1);
mt.setAdapter(adp);
}
public class AtTokenizer implements MultiAutoCompleteTextView.Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != '#')
i--;
while (i < cursor && text.charAt(i) == ' ')
i++;
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == '#') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ')
i--;
if (i > 0 && text.charAt(i-1) == '#') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text);
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
}
else {
return text;
}
}
}
}
I google'd while and i get the solution. I do code as below and its work for me.I just setup the auto-complete in our Activity onCreate() method.
In my case, i am using the # character to identify the start of pieces of text that should be lookedup and spaces to determine the end of the look up token.
public class MultiAutoCompleteTextViewDemo extends AppCompatActivity
{
MultiAutoCompleteTextView inputEditText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
inputEditText = (MultiAutoCompleteTextView) findViewById(R.id.multiAutoCompleteTextView1);
inputEditText.setTokenizer(new UsernameTokenizer());
inputEditText.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) {
int cursor = start;
if (cursor >= s.length()) cursor = s.length()-1;
if (isValidToken(s, cursor)){
String token = getToken(s, start);
new LinkedinSkillAsyncTask((Activity) getApplicationContext()).execute( token );
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
private boolean isValidToken(CharSequence text, int cursor){
for (int i=cursor; i>=0; i--){
if (text.charAt(i) == '#') return true;
if (text.charAt(i) == ' ') return false;
}
return false;
}
private String getToken(CharSequence text, int cursor){
int start=findTokenStart(text, cursor);
int end=findTokenEnd(text, cursor);
return text.subSequence(start, end).toString();
}
private int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != '#') { i--; }
return i;
}
private int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len && text.charAt(i) != ' ' && text.charAt(i) != ',' && text.charAt(i) != '.' ) {
i++;
}
return i;
}
public class UsernameTokenizer implements MultiAutoCompleteTextView.Tokenizer {
#Override public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') { i--; }
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(), Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
#Override public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != '#') {
i--;
}
if (i < 1 || text.charAt(i - 1) != '#') {
return cursor;
}
return i;
}
#Override public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
}
public class LinkedinSkillAsyncTask extends AsyncTask<String, String, String> {
private Activity context;
public String data;
public List<String> suggest;
public ArrayAdapter<String> aAdapter;
public LinkedinSkillAsyncTask(Activity cntxt) {
context = cntxt;
}
#Override protected String doInBackground(String... key) {
String newText = key[0];
newText = newText.trim();
newText = newText.replace(" ", "+");
try {
HttpClient hClient = new DefaultHttpClient();
HttpGet hGet = new HttpGet("http://www.linkedin.com/ta/skill?query="+newText);
ResponseHandler<String> rHandler = new BasicResponseHandler();
data = hClient.execute(hGet, rHandler);
suggest = new ArrayList<String>();
JSONObject jobj = new JSONObject(data);
JSONArray jArray = jobj.getJSONArray("resultList");
for (int i = 0; i < jArray.length(); i++) {
String SuggestKey = jArray.getJSONObject(i).getString("displayName");
suggest.add(SuggestKey);
}
} catch (Exception e) {
Log.w("Error", e.getMessage());
}
context.runOnUiThread(new Runnable() {
public void run() {
MultiAutoCompleteTextView inputEditText = (MultiAutoCompleteTextView) context.findViewById(R.id.multiAutoCompleteTextView1);
aAdapter = new ArrayAdapter<String>( context, android.R.layout.simple_dropdown_item_1line, suggest);
inputEditText.setAdapter(aAdapter);
aAdapter.notifyDataSetChanged();
}
});
return null;
}
}
}
For More detail you can read this tutorial. For example check this GitHub demo project.

Categories

Resources