Live editing of users input - android

Is it possible to auto insert characters into an EditText as the user inputs data?
I.e. if the user is entering a long number such as 123456789012, is it possible for this number to appear as he is typing it in the edit text box, but with a dash every 4th character?
So as you type the number above you would see it being entered in the EditText box but would look like this: 1234-5678-9012.
Currently I have an app where you can enter a long number and then press a button and it inserts the dashes for you, but I'm curious if it could be done as you type?
Many thanks for any help.

By tagging android, I think you are discussing about android editText, is so you can do it by listening the TextChangedListener,
EDITED: for backspace
editText.addTextChangedListener(new TextWatcher() {
int len=0;
#Override
public void afterTextChanged(Editable s) {
String str = editText.getText().toString();
if(str.length()==4&& len <str.length()){//len check for backspace
editText.append("-");
}
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
String str = editText.getText().toString();
len = str.length();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});

to solve this issue, i write a class "AutoAddTextWatcher" :
1. Auto insert text into EditText.
2. insert text into EditText at positions you are setted.
3. delete text in EditText at positions you are setted, when text length bigger than 1.
code snippet :
mEditText_birthday.addTextChangedListener(new AutoAddTextWatcher(mEditText_birthday,
"/",
new TextWatcher() {},
4, 6));
AutoAddTextWatcher class
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
/**
* Created by henry.chuang on 2016/5/12.
*/
public class AutoAddTextWatcher implements TextWatcher {
private CharSequence mBeforeTextChanged;
private TextWatcher mTextWatcher;
private int[] mArray_pos;
private EditText mEditText;
private String mAppentText;
public AutoAddTextWatcher(EditText editText, String appendText, int... position){
this.mEditText = editText;
this.mAppentText = appendText;
this.mArray_pos = position.clone();
}
public AutoAddTextWatcher(EditText editText, String appendText, TextWatcher textWatcher, int... position){
this(editText, appendText, position);
this.mTextWatcher = textWatcher;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
mBeforeTextChanged = s.toString();
if(mTextWatcher != null)
mTextWatcher.beforeTextChanged(s, start, count, after);
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
for (int i = 0; i < mArray_pos.length; i++) {
if(((mBeforeTextChanged.length() - mAppentText.length() * i) == (mArray_pos[i] - 1) &&
(s.length() - mAppentText.length() * i) == mArray_pos[i])){
mEditText.append(mAppentText);
break;
}
if(((mBeforeTextChanged.length() - mAppentText.length() * i) == mArray_pos[i] &&
(s.length() - mAppentText.length() * i) == (mArray_pos[i] + 1))){
int idx_start = mArray_pos[i] + mAppentText.length() * i;
int idx_end = Math.min(idx_start + mAppentText.length(), s.length());
String sub = mEditText.getText().toString().substring(idx_start, idx_end);
if(!sub.equals(mAppentText)){
mEditText.getText().insert(s.length() - 1, mAppentText);
}
break;
}
if(mAppentText.length() > 1 &&
(mBeforeTextChanged.length() - mAppentText.length() * i) == (mArray_pos[i] + mAppentText.length()) &&
(s.length() - mAppentText.length() * i) == (mArray_pos[i] + mAppentText.length() - 1)){
int idx_start = mArray_pos[i] + mAppentText.length() * i;
int idx_end = Math.min(idx_start + mAppentText.length(), s.length());
mEditText.getText().delete(idx_start, idx_end);
break;
}
}
if(mTextWatcher != null)
mTextWatcher.onTextChanged(s, start, before, count);
}
#Override
public void afterTextChanged(Editable s) {
if(mTextWatcher != null)
mTextWatcher.afterTextChanged(s);
}
}
complete demo source :
https://github.com/henrychuangtw/AutoInsertEditText

#Override
public void afterTextChanged(Editable s) {
if(s.length() == 3 && len < s.length()){
s.append(" - ");
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
len = s.length();
}
This will do as well, only this code will insert " - " after 3rd character.

This is what I used
private boolean mInEdit;
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!mInEdit) {
mInEdit = true;
String delimiter = " - ";
//Remove chars from your delimiter first
String digits = s.toString().replaceAll("[- ]", "")
.replaceAll("\\d{4}", "$0" + delimiter);
//Handle deletion
int dLength = delimiter.length();
if (before > count && digits.endsWith(delimiter.charAt(dLength - 1)) {
digits = digits.substring(0, digits.length() - dLength);
}
mCardNumber.setText(digits);
mCardNumber.setSelection(mCardNumber.length());
mInEdit = false;
}
}
Here you replace delimiter with what you want to separate digits.

For those still facing trouble with backspace and multiple hyphens -
new TextWatcher()
{
boolean hyphenExists;
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (s.length() >= 6 && s.charAt(5) == '-') {
hyphenExists = true;
} else {
hyphenExists = false;
}
Log.d("TAG", "beforeTextChanged " + s.toString());
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d("TAG", "onTextChanged " + s.toString());
}
#Override
public void afterTextChanged(Editable s) {
if (s.length() == 5) {
if (!hyphenExists)
s.append('-');
}
Log.d("TAG", "afterTextChanged " + s.toString());
}
}

You can achieve this with on text changed
in my case, i have to format input like this : xxx xxx-xxxx
i done as given below:
etMobileNumber.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 (etMobileNumber.text.length == 3 && count != 0) {
val text = etMobileNumber.getText().toString() + " "
etMobileNumber.setText(text)
etMobileNumber.setSelection(text.length)
} else if (etMobileNumber.text.length == 7 && count != 0) {
val text = etMobileNumber.getText().toString() + "-"
etMobileNumber.setText(text)
etMobileNumber.setSelection(text.length)
}
}
})
and the result is very dynamic on the go while typing.
input- 1234567890
result - 123 456-7890

Related

Cyclical replacement the content of EditText with the limited length

For example, I have EditText with length limitation of two characters. When the first and second letters entered it's ok. But when we will try to enter a third letter the first letter should be replaced with it. Next letter should replace the second and so on in a circle. How can I do this one.
Try using TextWatcher on your edit text to achieve the goal
editText.addTextChangedListener(new TextWatcher() {
private int lastModifiedIndex = 1;
#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() > 2) {
char toReplace = s.charAt(s.length() - 1);
if (lastModifiedIndex == 0) {
editText.setText("" + s.charAt(lastModifiedIndex) + toReplace);
lastModifiedIndex = 1;
editText.setSelection(s.length());
} else {
editText.setText("" + toReplace + s.charAt(lastModifiedIndex));
lastModifiedIndex = 0;
editText.setSelection(s.length());
}
} else {
lastModifiedIndex = 1;
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
Try this one
editText.addTextChangedListener(new TextWatcher() {
private int charLimit = 5;
private int position = 5;
private String newSequence;
#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() > charLimit ) {
if (position == charLimit) {
newSequence = s.subSequence(s.length()-1, s.length()).toString() +
s.subSequence(1, charLimit);
position = 1;
} else {
position++;
newSequence = s.subSequence(0, position).toString() +
s.subSequence(position+1, s.length());
}
editText.setText(null);
editText.setText(newSequence);
editText.setSelection(position);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});

android TextWatcher beforeTextChanged problem

in my application i have many edit text and i implemented textWatcher for them i want them to increase and decrease a textView number but i can only increase it
i tried to check if the old text is bigger that new text and decrease the textview number, but it returns false everytime
my code :
editText.addTextChangedListener(new TextWatcher() {
String oldText = "";
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
this.oldText = s.toString();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (!editText.getText().toString().equals("")) {
int price = Integer.parseInt(editText.getText().toString()) * price_db;
productPrice.setText(price + "");
int totalPrice_n = Integer.parseInt(totalPrice.getText().toString());
int min = Integer.parseInt(editText.getText().toString()) - Integer.parseInt(oldText);
if(Integer.parseInt(editText.getText().toString()) > Integer.parseInt(oldText)){
totalPrice.setText((totalPrice_n + min * price_db) + "");
}else{
totalPrice.setText((totalPrice_n - min * price_db) + "");
}
}
}
});
my problem is that if condition only returns false and goes to else part, also my EditText default text is set to 0 so i think beforeTextChanged only take on 0 and check if new text is bigger than 0
i change editText's text with 2 button ( + , - ) and i want when i click on + button to increase the TextView number and also when i click on - button to decrease TextView number but it only increase it i dont know why
Replace my code with your code and check dude !!! :)
editText.addTextChangedListener(new TextWatcher() {
String oldText = "";
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
this.oldText = s.toString();
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (!editText.getText().toString().equalsIgnoreCase(""))
{
int amount=Integer.parseI`enter code here`nt(editText.getText().toString());
int price = Integer.parseInt(editText.getText().toString()) * price_db;
int totalPrice_n = Integer.parseInt(totalPrice.getText().toString());
productPrice.setText(price);
int min = amount - Integer.parseInt(oldText);
if(Integer.parseInt(oldText) > 0)
{
if(amount > Integer.parseInt(oldText)){
totalPrice.setText((totalPrice_n + min * price_db));
}else{
totalPrice.setText((totalPrice_n - min * price_db));
}
}
else
Toast.makeText(context,"old text is 0",Toast.LENGTH_LONG).show();
}
}
});

Limit a EditText to exactly certain number of word count

How can we limit the EditText length to certain number of word count (100 words).
Even though copy a large text from some where,while pasting it should accept only 100 words.
I know we can limit it by character count (maxLength)
I tried with below code, but it doesn't limit it by exactly 100 words and it is allowing copy-paste large text.
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
int wordsLength = countWords(charSequence.toString());// words.length;
// count == 0 means a new word is going to start
if (count == 0 && wordsLength >= MAX_WORD_LIMIT) {
int charLength = mDescription.getText().length();
setCharLimit(mDescription, charLength > 0 ? charLength - 2 : charLength);
} else {
removeFilter(mDescription);
}
and
private InputFilter filter;
private void setCharLimit(EditText et, int max) {
filter = new InputFilter.LengthFilter(max);
et.setFilters(new InputFilter[]{filter});
}
private void removeFilter(EditText et) {
if (filter != null) {
et.setFilters(new InputFilter[0]);
filter = null;
}
}
edittext.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
//To fix word count
String yourText= editText.getText().toString().replace(String.valueOf((char) 160), " ");
if (yourText.split("\\s+").length > MAX_WORD_LIMIT ) {
int space = 0;
int length = 0;
for (int i = 0; i < yourText.length(); i++) {
if (yourText.charAt(i) == ' ') {
space++;
if (space >= MAX_WORD_LIMIT) {
length = i;
break;
}
}
}
if (length > 1) {
editText.getText().delete(length, yourSelf.length()); // deleting last space
setCharLimit(editText, length - 1); //or limit edit text
}
} else {
removeFilter(editText);
}
}
#Override
public void afterTextChanged(Editable s) {
});
private InputFilter filter;
private void setCharLimit(EditText et, int max) {
filter = new InputFilter.LengthFilter(max);
et.setFilters(new InputFilter[] { filter });
}
private void removeFilter(EditText et) {
if (filter != null) {
et.setFilters(new InputFilter[0]);
filter = null;
}
}
here 160 is the non breaking space
You can do this by using:
android:maxLength="50"
in your EditText.
Hope its work for you
edittext.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) {
}
#Override
public void afterTextChanged(Editable s) {
// Check your edittext length here
if (edittext.getText().toString().length() > 100)
edittext.setText(edittext.getText().toString().substring(0, 100);
}
});
Kotlin Language -- To check maximum words need to check total space
--> Step-1
var filter: InputFilter?=null
--> Step-2
edt.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
var count : Int = 0
if(s.toString().length > 0)
for(i in 0..s.toString().length-1){
if(s.toString()[i].toString() == " "){
count++
}
if(i > 1 && s.toString()[i-1].toString() == " " && s.toString()[i].toString() == " "){
count--
}
}
if (count >= MAX_COUNTS_WORDS){
filter = InputFilter.LengthFilter(edt.text.toString().length)
edt.filters = arrayOf<InputFilter>(filter ?: return)
}
else if (filter != null) {
edt.filters = arrayOfNulls(0)
filter = null
}
}
override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
If you want to find word count then you can use java logic.
String text = "More than 100 word sentence";
String[] txtArr = text.split(" ");
Now Pick only first 100 index words.
This is just a hack. May be there are more optimal ways out there.
You can use split with index of functions. Sorry for so long string, hope you will get the idea. Just extract some variables.
edittext.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) {
}
#Override
public void afterTextChanged(Editable s) {
if (edittext.getText().toString().split(" ").size() > 100)
edittext.setText(edittext.getText().toString().substring(0, edittext.getText().toString().indexOf(edittext.getText().toString().split(" ").get(100))));
}
});
use android:maxLength property of edittext to solve your problem.

Custom format edit text input android to accept credit card number

how to make edit text accept input in format
4digitnumber-4dignumber-4dignumber-4dignumber
The code
text.addTextChangedListener(new TextWatcher() {
int len = 0;
String string ;
#Override
public void afterTextChanged(Editable s) {
text.setOnKeyListener(new OnKeyListener()
{ public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_DEL)
{
}
else{
string = text.getText().toString();
len = string.length()+1;
if(len%5==0){text.append("-");}
}
return false; } });
}
});
works fine upon adding, but deleting or editing causes problem.
Now this works fine for soft/hard keyboard for all delete/edit ops.
tx 4 ur help..
package com.and;
import android.app.Activity;
import android.app.AlertDialog;
import android.inputmethodservice.KeyboardView;
import android.os.Bundle;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.text.format.Formatter;
import android.text.method.NumberKeyListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.Toast;
public class ccformat extends Activity {
String a;
int keyDel;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final EditText text = (EditText) findViewById(com.and.R.id.editText1);
text.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
boolean flag = true;
String eachBlock[] = text.getText().toString().split("-");
for (int i = 0; i < eachBlock.length; i++) {
if (eachBlock[i].length() > 4) {
flag = false;
}
}
if (flag) {
text.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL)
keyDel = 1;
return false;
}
});
if (keyDel == 0) {
if (((text.getText().length() + 1) % 5) == 0) {
if (text.getText().toString().split("-").length <= 3) {
text.setText(text.getText() + "-");
text.setSelection(text.getText().length());
}
}
a = text.getText().toString();
} else {
a = text.getText().toString();
keyDel = 0;
}
} else {
text.setText(a);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
}
This is working:
public class EditTextSample extends Activity {
// This regexp has to be improved, it does not detect case where you have
// more than 4 digits in a middle group like: 1234-12345-123
static final Pattern CODE_PATTERN = Pattern.compile("([0-9]{0,4})|([0-9]{4}-)+|([0-9]{4}-[0-9]{0,4})+");
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.edit_text_sample);
final EditText editText = (EditText) findViewById(R.id.input);
editText.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
Log.w("", "input" + s.toString());
if (s.length() > 0 && !CODE_PATTERN.matcher(s).matches()) {
String input = s.toString();
String numbersOnly = keepNumbersOnly(input);
String code = formatNumbersAsCode(numbersOnly);
Log.w("", "numbersOnly" + numbersOnly);
Log.w("", "code" + code);
editText.removeTextChangedListener(this);
editText.setText(code);
// You could also remember the previous position of the cursor
editText.setSelection(code.length());
editText.addTextChangedListener(this);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
private String keepNumbersOnly(CharSequence s) {
return s.toString().replaceAll("[^0-9]", ""); // Should of course be more robust
}
private String formatNumbersAsCode(CharSequence s) {
int groupDigits = 0;
String tmp = "";
for (int i = 0; i < s.length(); ++i) {
tmp += s.charAt(i);
++groupDigits;
if (groupDigits == 4) {
tmp += "-";
groupDigits = 0;
}
}
return tmp;
}
});
}
}
If you want to just group visually the numbers, but you don't want to alter the value of the EditText adding dashes, you can use this Span approach:
EditText editText = findViewById(R.id.editText);
editText.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) {}
#Override
public void afterTextChanged(Editable editable) {
Object[] paddingSpans = editable.getSpans(0, editable.length(), DashSpan.class);
for (Object span : paddingSpans) {
editable.removeSpan(span);
}
addSpans(editable);
}
private static final int GROUP_SIZE = 4;
private void addSpans(Editable editable) {
final int length = editable.length();
for (int i = 1; i * (GROUP_SIZE) < length; i++) {
int index = i * GROUP_SIZE;
editable.setSpan(new DashSpan(), index - 1, index,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
});
where the DashSpan class looks like this:
/**
* A {#link ReplacementSpan} used for spacing in {#link android.widget.EditText}
* to space things out. Adds '-'s
*/
public class DashSpan extends ReplacementSpan {
#Override
public int getSize(#NonNull Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
float padding = paint.measureText("-", 0, 1);
float textSize = paint.measureText(text, start, end);
return (int) (padding + textSize);
}
#Override
public void draw(#NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
int bottom, #NonNull Paint paint) {
canvas.drawText(text.subSequence(start, end) + "-", x, y, paint);
}
}
This way you will have visually the grouping using the dashes, but the getText() will return the text without any grouping.
To force only numbers you can add the attributes android:digits="0123456789" and android:inputType="number" to the EditText.
This solution is based on the code of this library.
In my case below code is working fine.
editTextCreditCard.addTextChangedListener(new FourDigitCardFormatWatcher());
Add custom class for TextWatcher.
public class FourDigitCardFormatWatcher implements TextWatcher {
private static final char space = ' ';
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
if (s.length() > 0 && (s.length() % 5) == 0) {
final char c = s.charAt(s.length() - 1);
if (space == c) {
s.delete(s.length() - 1, s.length());
}
}
if (s.length() > 0 && (s.length() % 5) == 0) {
char c = s.charAt(s.length() - 1);
if (Character.isDigit(c) && TextUtils.split(s.toString(), String.valueOf(space)).length <= 3) {
s.insert(s.length() - 1, String.valueOf(space));
}
}
}
}
Hope this would help you.
It works in all cases, when you insert or remove a character, the format will always be right. Make sure you set
android:inputType="number"
/
myEditText.addTextChangedListener(new TextWatcher() {
private final String space = "-"; // you can change this to whatever you want
private final Pattern pattern = Pattern.compile("^(\\d{4}"+space+"{1}){0,3}\\d{1,4}$"); // check whether we need to modify or not
#Override
public void onTextChanged(CharSequence s, int st, int be, int count) {
String currentText = myEditText.getText().toString();
if (currentText.isEmpty() || pattern.matcher(currentText).matches())
return; // no need to modify
String numbersOnly = currentText.trim().replaceAll("[^\\d.]", "");; // remove everything but numbers
String formatted = "";
for(int i = 0; i < numbersOnly.length(); i += 4)
if (i + 4 < numbersOnly.length())
formatted += numbersOnly.substring(i,i+4)+space;
else
formatted += numbersOnly.substring(i);
myEditText.setText(formatted);
myEditText.setSelection(myEditText.getText().toString().length());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
public void afterTextChanged(Editable e) {}
});
It seems to me the answers presented here do not work properly with delete, delete from the middle operations, etc.
Here is my code. It doesn't restrict the length of input, but seems to be ok with various insertions and deletions:
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
public class HyphenDelimitTextWatcher implements TextWatcher {
EditText mEditText;
boolean mInside = false;
boolean mWannaDeleteHyphen = false;
boolean mKeyListenerSet = false;
final static String MARKER = "|"; // filtered in layout not to be in the string
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if(!mKeyListenerSet) {
mEditText.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
try {
mWannaDeleteHyphen = (keyCode == KeyEvent.KEYCODE_DEL
&& mEditText.getSelectionEnd() - mEditText.getSelectionStart() <= 1
&& mEditText.getSelectionStart() > 0
&& mEditText.getText().toString().charAt(mEditText.getSelectionEnd() - 1) == '-');
} catch (IndexOutOfBoundsException e) {
// never to happen because of checks
}
return false;
}
});
mKeyListenerSet = true;
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (mInside) // to avoid recursive calls
return;
mInside = true;
int currentPos = mEditText.getSelectionStart();
String string = mEditText.getText().toString().toUpperCase();
String newString = makePrettyString(string);
mEditText.setText(newString);
try {
mEditText.setSelection(getCursorPos(string, newString, currentPos, mWannaDeleteHyphen));
} catch (IndexOutOfBoundsException e) {
mEditText.setSelection(mEditText.length()); // last resort never to happen
}
mWannaDeleteHyphen = false;
mInside = false;
}
#Override
public void afterTextChanged(Editable s) {
}
private String makePrettyString(String string) {
String number = string.replaceAll("-", "");
boolean isEndHyphen = string.endsWith("-") && (number.length()%4 == 0);
return number.replaceAll("(.{4}(?!$))", "$1-") + (isEndHyphen ?"-":"");
}
private int getCursorPos(String oldString, String newString, int oldPos, boolean isDeleteHyphen) {
int cursorPos = newString.length();
if(oldPos != oldString.length()) {
String stringWithMarker = oldString.substring(0, oldPos) + MARKER + oldString.substring(oldPos);
cursorPos = (makePrettyString(stringWithMarker)).indexOf(MARKER);
if(isDeleteHyphen)
cursorPos -= 1;
}
return cursorPos;
}
public HyphenDelimitTextWatcher(EditText editText) {
mEditText = editText;
}
}
Usage:
mSomeEditText.addTextChangedListener(new HyphenDelimitTextWatcher(mSomeEditText));
if you neeed this efect,ou can use this code in EditText
Here is a formatting regex used to show card details in format XXXX XXXX XXXX XXXX
etCreditCardNumber.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) {
etCreditCardNumber.setFloatingLabel(MaterialEditText.FLOATING_LABEL_HIGHLIGHT);
String initial = s.toString();
// remove all non-digits characters
String processed = initial.replaceAll("\\D", "");
// insert a space after all groups of 4 digits that are followed by another digit
processed = processed.replaceAll("(\\d{4})(?=\\d)(?=\\d)(?=\\d)", "$1 ");
//Remove the listener
etCreditCardNumber.removeTextChangedListener(this);
int index = etCreditCardNumber.getSelectionEnd();
if (index == 5 || index == 10 || index == 15)
if (count > before)
index++;
else
index--;
//Assign processed text
etCreditCardNumber.setText(processed);
try {
etCreditCardNumber.setSelection(index);
} catch (Exception e) {
e.printStackTrace();
etCreditCardNumber.setSelection(s.length() - 1);
}
//Give back the listener
etCreditCardNumber.addTextChangedListener(this);
}
#Override
public void afterTextChanged(Editable s) {
}
});

Android Money Input with fixed decimal

How do you create an edittext entry that formats input in money format only? When the user enters 5, I want the input to look like "$0.05" and when they then enter 3, the input should now look like "$0.53" and finally they enter 6 and the input should look like "$5.36".
ninjasense's complete solution basically works, but it has some issues:
Every time the data of the field is altered in the "onTextChanged" handler, cursor position resets to index 0 on the field, which is a bit annoying to happen when typing in monetary values.
It uses floats for formatting monetary values, which can backfire.
For the first problem I don't have solution yet, for the second one code like this works:
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if(!s.toString().matches("^\\$(\\d{1,3}(\\,\\d{3})*|(\\d+))(\\.\\d{2})?$"))
{
String userInput= ""+s.toString().replaceAll("[^\\d]", "");
StringBuilder cashAmountBuilder = new StringBuilder(userInput);
while (cashAmountBuilder.length() > 3 && cashAmountBuilder.charAt(0) == '0') {
cashAmountBuilder.deleteCharAt(0);
}
while (cashAmountBuilder.length() < 3) {
cashAmountBuilder.insert(0, '0');
}
cashAmountBuilder.insert(cashAmountBuilder.length()-2, '.');
cashAmountBuilder.insert(0, '$');
cashAmountEdit.setText(cashAmountBuilder.toString());
}
}
Building off Zds.
For keeping the cursor positioned at the end of the field use this.
cashAmountEdit.setTextKeepState(cashAmountBuilder.toString());
Selection.setSelection(cashAmountEdit.getText(), cashAmountBuilder.toString().length());
You can use a TextWatcher to do that kind of thing.
Extend TextWatcher: http://d.android.com/reference/android/text/TextWatcher.html
public class MyTextWatcher implements TextWatcher {
public void afterTextChanged(Editable arg0) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}
Then add it to your editText with
myEditText.addTextChangedListener(new MyTextWatcher());
I found the TextWatcher to be a bit cumbersome. Instead, you can set the key listener:
setKeyListener(new CalculatorKeyListener());
// Must be called after setKeyListener(), otherwise is overridden
setRawInputType(Configuration.KEYBOARD_12KEY);
And then create a KeyListener which extends NumberKeyListener:
class CalculatorKeyListener extends NumberKeyListener {
#Override
public int getInputType() {
return InputType.TYPE_CLASS_NUMBER;
}
#Override
public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
digitPressed(keyCode - KeyEvent.KEYCODE_0);
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
deletePressed();
}
return true;
}
#Override
protected char[] getAcceptedChars() {
return new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
}
}
You then need to display the characters correctly, but that's not difficult; just keep track of cents, and then divide or multiply by 10, and use a NumberFormat to get the formatting correct.
Heres my complete solution:
tvValue.setRawInputType(Configuration.KEYBOARD_12KEY);
tvValue.addTextChangedListener(new TextWatcher(){
#Override
public void afterTextChanged(Editable arg0) {
// 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 onTextChanged(CharSequence s, int start,
int before, int count) {
// TODO Auto-generated method stub
// here i converted to string
if(!s.toString().matches("^\\$(\\d{1,3}(\\,\\d{3})*|(\\d+))(\\.\\d{2})?$"))
{
String userInput= ""+s.toString().replaceAll("[^\\d]", "");
Float in=Float.parseFloat(userInput);
float percen = in/100;
tvValue.setText("$"+percen);
}
}
});
I did this but without decimal and with dot for miles, check the code and add the functionality to support decimals.
MyEditText.addTextChangedListener(new TextWatcher()
{
#Override
public void onTextChanged(CharSequence s, int start, int before, int count){
if(s.toString().length() > 0){
MyEditText.removeTextChangedListener(this);
String numbers = removeCharacters(s.toString());
int money = 0;
try{
money = Integer.parseInt(numbers);
}
catch(Exception ex){
money = 0;
}
MyEditText.setText(getMoney(money));
//Set cursor on correct position
int selection = start;
if(count > 0){
selection++;
if(MyEditText.getText().toString().length() == 2 || MyEditText.getText().toString().length() == 6 || MyEditText.getText().toString().length() == 10){
selection++;
}
}
else{
if(MyEditText.getText().toString().length() == 4 || MyEditText.getText().toString().length() == 8){
selection--;
}
}
if(selection > MyEditText.getText().toString().length()){
selection = MyEditText.getText().toString().length();
}
MyEditText.setSelection(selection);
MyEditText.addTextChangedListener(this);
}
if(s.toString().length() == 1 && count < 1 && start == 1){
MyEditText.removeTextChangedListener(this);
MyEditText.setText("");
MyEditText.addTextChangedListener(this);
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after){
}
#Override
public void afterTextChanged(Editable s)
{
}
});
public String removeCharacters(String money){
int i=0;
while (i<money.length())
{
Character c = money.charAt(i);
if (Character.isDigit(c) && c != '.')
{
i++;
}
else
{
money = money.replace(c.toString(), "");
}
}
return money;
}
public String getMoney(int value){
String money = "$";
NumberFormat numberFormatter;
numberFormatter = NumberFormat.getNumberInstance(Locale.GERMAN);
money += numberFormatter.format(value);
return money;
}
This answer is based on Zds' answer (which in turn was based on ninjasense's answer), but this should resolve the cursor position issue:
if(!text.matches("^\\$(\\d{1,2})(\\.\\d{2})?$")) {
int originalCursorPosition = view.getSelectionStart();
int cursorOffset = 0;
boolean cursorAtEnd = originalCursorPosition == text.length();
String userInput= ""+text.replaceAll("[^\\d]", "");
StringBuilder cashAmountBuilder = new StringBuilder(userInput);
while (cashAmountBuilder.length() > 3 && cashAmountBuilder.charAt(0) == '0') {
cashAmountBuilder.deleteCharAt(0);
cursorOffset--;
}
while (cashAmountBuilder.length() < 3) {
cashAmountBuilder.insert(0, '0');
cursorOffset++;
}
cashAmountBuilder.insert(cashAmountBuilder.length() - 2, '.');
cashAmountBuilder.insert(0, '$');
view.setText(cashAmountBuilder.toString());
view.setSelection(cursorAtEnd ? view.getText().length() : originalCursorPosition + cursorOffset);
}
Notes:
The following is in a TextWatcher.onTextChanged
I'm using a different regex than other answers, which keeps the price to < $100
'view' is the editText, 'text' is the string contents
this has worked for me using an EditText with a maxLength of 6 (i.e. $00.00)

Categories

Resources