I have an EditText in which the user should input a number including decimals and i want a thousand separator automatically added onto the input number I tried a couple of other methods but some do not allow floating point numbers so i came up with this code which works well only that the string input is not being edited in realtime to one with possible thousand separators and the errors seem to stem from the s.replace();
am2 = new TextWatcher(){
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) {
if (s.toString().equals("")) {
amount.setText("");
value = 0;
}else{
StringBuffer strBuff = new StringBuffer();
char c;
for (int i = 0; i < amount2.getText().toString().length() ; i++) {
c = amount2.getText().toString().charAt(i);
if (Character.isDigit(c)) {
strBuff.append(c);
}
}
value = Double.parseDouble(strBuff.toString());
reverse();
NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
((DecimalFormat)nf2).applyPattern("###,###.#######");
s.replace(0, s.length(), nf2.format(value));
}
}
};
This Class solves the problem, allows decimal input and adds the thousand separators.
public class NumberTextWatcher implements TextWatcher {
private DecimalFormat df;
private DecimalFormat dfnd;
private boolean hasFractionalPart;
private EditText et;
public NumberTextWatcher(EditText et)
{
df = new DecimalFormat("#,###.##");
df.setDecimalSeparatorAlwaysShown(true);
dfnd = new DecimalFormat("#,###");
this.et = et;
hasFractionalPart = false;
}
#SuppressWarnings("unused")
private static final String TAG = "NumberTextWatcher";
public void afterTextChanged(Editable s)
{
et.removeTextChangedListener(this);
try {
int inilen, endlen;
inilen = et.getText().length();
String v = s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()), "");
Number n = df.parse(v);
int cp = et.getSelectionStart();
if (hasFractionalPart) {
et.setText(df.format(n));
} else {
et.setText(dfnd.format(n));
}
endlen = et.getText().length();
int sel = (cp + (endlen - inilen));
if (sel > 0 && sel <= et.getText().length()) {
et.setSelection(sel);
} else {
// place cursor at the end?
et.setSelection(et.getText().length() - 1);
}
} catch (NumberFormatException nfe) {
// do nothing?
} catch (ParseException e) {
// do nothing?
}
et.addTextChangedListener(this);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if (s.toString().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
{
hasFractionalPart = true;
} else {
hasFractionalPart = false;
}
}
}
Source: http://blog.roshka.com/2012/08/android-edittext-with-number-format.html
Unfortunately the code did not work as it is in the answer.
It has two problems:
It does not work if the phone locale configuration uses "," as a decimal separator.
It does not work if the number has trailing zeros in the decimal part. Example 1.01.
I went crazy to fix it.
Finally I came to this code that worked well on my cell phone:
NumberTextWatcher.java
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.util.Log;
import android.widget.EditText;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;
public class NumberTextWatcher
implements TextWatcher {
private static final String TAG = "NumberTextWatcher";
private final int numDecimals;
private String groupingSep;
private String decimalSep;
private boolean nonUsFormat;
private DecimalFormat df;
private DecimalFormat dfnd;
private boolean hasFractionalPart;
private EditText et;
private String value;
private String replicate(char ch, int n) {
return new String(new char[n]).replace("\0", "" + ch);
}
public NumberTextWatcher(EditText et, Locale locale, int numDecimals) {
et.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));
this.numDecimals = numDecimals;
DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
char gs = symbols.getGroupingSeparator();
char ds = symbols.getDecimalSeparator();
groupingSep = String.valueOf(gs);
decimalSep = String.valueOf(ds);
String patternInt = "#,###";
dfnd = new DecimalFormat(patternInt, symbols);
String patternDec = patternInt + "." + replicate('#', numDecimals);
df = new DecimalFormat(patternDec, symbols);
df.setDecimalSeparatorAlwaysShown(true);
df.setRoundingMode(RoundingMode.DOWN);
this.et = et;
hasFractionalPart = false;
nonUsFormat = !decimalSep.equals(".");
value = null;
}
#Override
public void afterTextChanged(Editable s) {
Log.d(TAG, "afterTextChanged");
et.removeTextChangedListener(this);
try {
int inilen, endlen;
inilen = et.getText().length();
String v = value.replace(groupingSep, "");
Number n = df.parse(v);
int cp = et.getSelectionStart();
if (hasFractionalPart) {
int decPos = v.indexOf(decimalSep) + 1;
int decLen = v.length() - decPos;
if (decLen > numDecimals) {
v = v.substring(0, decPos + numDecimals);
}
int trz = countTrailingZeros(v);
StringBuilder fmt = new StringBuilder(df.format(n));
while (trz-- > 0) {
fmt.append("0");
}
et.setText(fmt.toString());
} else {
et.setText(dfnd.format(n));
}
endlen = et.getText().length();
int sel = (cp + (endlen - inilen));
if (sel > 0 && sel <= et.getText().length()) {
et.setSelection(sel);
} else {
// place cursor at the end?
et.setSelection(et.getText().length() - 1);
}
} catch (NumberFormatException | ParseException nfe) {
// do nothing?
}
et.addTextChangedListener(this);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d(TAG, "beforeTextChanged");
value = et.getText().toString();
}
private int countTrailingZeros(String str) {
int count = 0;
for (int i = str.length() - 1; i >= 0; i--) {
char ch = str.charAt(i);
if ('0' == ch) {
count++;
} else {
break;
}
}
return count;
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.d(TAG, "onTextChanged");
String newValue = s.toString();
String change = newValue.substring(start, start + count);
String prefix = value.substring(0, start);
String suffix = value.substring(start + before);
if (".".equals(change) && nonUsFormat) {
change = decimalSep;
}
value = prefix + change + suffix;
hasFractionalPart = value.contains(decimalSep);
Log.d(TAG, "VALUE: " + value);
}
}
and then to use it simply to do:
Locale locale = new Locale("es", "AR"); // For example Argentina
int numDecs = 2; // Let's use 2 decimals
TextWatcher tw = new NumberTextWatcher(myEditText, locale, numDecs);
myEditText.addTextChangedListener(tw);
You need to use DecimalFormat class with DecimalFormatSymbols class, check the out following method,
public static String formatAmount(int num)
{
DecimalFormat decimalFormat = new DecimalFormat();
DecimalFormatSymbols decimalFormateSymbol = new DecimalFormatSymbols();
decimalFormateSymbol.setGroupingSeparator(',');
decimalFormat.setDecimalFormatSymbols(decimalFormateSymbol);
return decimalFormat.format(num);
}
you can use kotlin extensions function like this...
fun EditText.onCommaChange(input: (String) -> Unit) {
this.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
if (!edit) {
edit = true
if (s.toString() != "₹") {
try {
val flNumber = getCommaLessNumber(s.toString()).toInt()
val fNumber = getFormattedAmount(flNumber)
setText(fNumber)
setSelection(text.length)
input(flNumber.toString())
} catch (e: NumberFormatException) {
Timber.e(e)
}
} else {
setText("")
input("")
}
edit = false
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
})}
fun getCommaLessNumber(commaNumber: String): String {
var number = commaNumber.replace("₹", "")
number = number.replace(",".toRegex(), "")
return number}
fun getFormattedAmount(amount: Int): String {
return "₹${String.format("%,d", amount)}"}
fun EditText.text() = this.text.toString()
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import java.text.DecimalFormat;
public class MyNumberWatcher_3Digit implements TextWatcher {
private EditText editText;
private int digit;
public MyNumberWatcher_3Digit(EditText editText) {
this.editText = 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 editable) {
editText.removeTextChangedListener( this );
String s = editText.getText().toString();
s = s.replace( ",", "" ).replace( "٬", "" );
s = replaceNonstandardDigits( s );
if (s.length() > 0) {
DecimalFormat sdd = new DecimalFormat( "#,###" );
Double doubleNumber = Double.parseDouble( s );
String format = sdd.format( doubleNumber );
editText.setText( format );
editText.setSelection( format.length() );
}
editText.addTextChangedListener( this );
}
static String replaceNonstandardDigits(String input) {
if (input == null || input.isEmpty()) {
return input;
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt( i );
if (isNonstandardDigit( ch )) {
int numericValue = Character.getNumericValue( ch );
if (numericValue >= 0) {
builder.append( numericValue );
}
} else {
builder.append( ch );
}
}
return builder.toString();
}
private static boolean isNonstandardDigit(char ch) {
return Character.isDigit( ch ) && !(ch >= '0' && ch <= '9');
}
}
// oncreate activity
input_text_rate.addTextChangedListener(new MyNumberWatcher_3Digit(input_text_rate));
I used this way in Kotlin for a Dialog:
val et = dialog.findViewById(R.id.etNumber) as EditText
et.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {
et.removeTextChangedListener(this)
forChanged(et)
et.addTextChangedListener(this)
}
override fun beforeTextChanged(
s: CharSequence,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
}
})
then write a method like this:
private fun forChanged(alpha: EditText) {
val string = alpha.text.toString()
val dec = DecimalFormat("#,###")
if (!TextUtils.isEmpty(string)) {
val textWC = string.replace(",".toRegex(), "")
val number = textWC.toDouble()
alpha.setText(dec.format(number))
alpha.setSelection(dec.format(number).length)
}
}
I have tried solutions but with ending 0 i was having problem, sometimes user just wanted to enter 0.01 or 0.0001,
I don't know if any other have posted same answer or not but if this helps,
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;
import java.text.DecimalFormat;
public class NumberTextWatcher implements TextWatcher {
private DecimalFormat dfnd;
private boolean hasFractionalPart;
private EditText inputView;
public static void bindView(EditText inputView) {
NumberTextWatcher temp = new NumberTextWatcher(inputView);
inputView.addTextChangedListener(temp);
}
public NumberTextWatcher(EditText inputView) {
dfnd = new DecimalFormat("#,###.######");
this.inputView = inputView;
hasFractionalPart = false;
}
#SuppressWarnings("unused")
private static final String TAG = "NumberTextWatcher";
public void afterTextChanged(Editable s) {
Log.d(TAG, "afterTextChanged() called with: s = [" + s + "]");
inputView.removeTextChangedListener(this);
try {
String text = inputView.getText().toString().replace(String.valueOf(dfnd.getDecimalFormatSymbols().getGroupingSeparator()), "");
if(text.charAt(text.length() - 1) == '.')
{
if(getCount(text,'.') >1)
{
text = text.substring(0,text.length()-1);
}
}
String afterDecimalPoint = "";
String beforeDecimalPoint = text;
if (hasFractionalPart || (text.charAt(text.length() - 1) == '0')) {
String[] data = text.split("\\.");
beforeDecimalPoint = data[0];
if (data.length != 2) {
afterDecimalPoint = ".";
} else {
afterDecimalPoint = "." + data[1];
if (data[1].length() >= dfnd.getMaximumFractionDigits()) {
afterDecimalPoint = "." + data[1].substring(0, dfnd.getMaximumFractionDigits());
}
}
}
beforeDecimalPoint = dfnd.format(Double.parseDouble(beforeDecimalPoint));
String finalText = beforeDecimalPoint;
if (hasFractionalPart) {
finalText = beforeDecimalPoint + afterDecimalPoint;
}
inputView.setText(finalText);
inputView.setSelection(finalText.length());
} catch (Exception nfe) {
// do nothing?
nfe.printStackTrace();
}
inputView.addTextChangedListener(this);
}
private int getCount(String someString, char someChar) {
int count = 0;
for (int i = 0; i < someString.length(); i++) {
if (someString.charAt(i) == someChar) {
count++;
}
}
return count;
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().contains(String.valueOf(dfnd.getDecimalFormatSymbols().getDecimalSeparator()))) {
hasFractionalPart = true;
} else {
hasFractionalPart = false;
}
}
}
Related
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))
}
I want to separate automatically edit text like (9,99,999) like this. I searched for this on the web but I have not found a proper solution for this.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText editText = (EditText) findViewById(R.id.edittext);
editText.addTextChangedListener(new NumberTextWatcherForThousand(editText)); NumberTextWatcherForThousand.trimCommaOfString(editText.getText().toString());
}
}
NumberTextWatcherForThousand
public class NumberTextWatcherForThousand implements TextWatcher {
EditText editText;
public NumberTextWatcherForThousand(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 != null && !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);
return;
}
catch (Exception ex)
{
ex.printStackTrace();
editText.addTextChangedListener(this);
}
}
public 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++;
}
}
public static String trimCommaOfString(String string) {
if(string.contains(",")){
return string.replace(",","");}
else {
return string;
}
}
}
This will format the text and add commas in thousands place inside your edit text.
#Override
public void afterTextChanged(Editable editable) {
try {
// The comma in the format specifier does the trick
editText.setText(String.format("%,d", Long.parseLong(editable.toString())));
} catch (NumberFormatException e) {
}
}
try this below code :-
import java.text.DecimalFormat;
import java.text.ParseException;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
public class NumberTextWatcher implements TextWatcher {
private DecimalFormat df;
private DecimalFormat dfnd;
private boolean hasFractionalPart;
private EditText et;
public NumberTextWatcher(EditText et)
{
df = new DecimalFormat("#,###.##");
df.setDecimalSeparatorAlwaysShown(true);
dfnd = new DecimalFormat("#,###");
this.et = et;
hasFractionalPart = false;
}
#SuppressWarnings("unused")
private static final String TAG = "NumberTextWatcher";
#Override
public void afterTextChanged(Editable s)
{
et.removeTextChangedListener(this);
try {
int inilen, endlen;
inilen = et.getText().length();
String v = s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()), "");
Number n = df.parse(v);
int cp = et.getSelectionStart();
if (hasFractionalPart) {
et.setText(df.format(n));
} else {
et.setText(dfnd.format(n));
}
endlen = et.getText().length();
int sel = (cp + (endlen - inilen));
if (sel > 0 && sel <= et.getText().length()) {
et.setSelection(sel);
} else {
// place cursor at the end?
et.setSelection(et.getText().length() - 1);
}
} catch (NumberFormatException nfe) {
// do nothing?
} catch (ParseException e) {
// do nothing?
}
et.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)
{
if (s.toString().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
{
hasFractionalPart = true;
} else {
hasFractionalPart = false;
}
}
}
and in your edittext
editText.addTextChangedListener(new NumberTextWatcher(editText));
In build.gradle add following lines
repositories{
maven { url "https://jitpack.io" }
}
dependencies {
compile 'com.github.BlacKCaT27:CurrencyEditText:v1.4.4'
}
Instead of EditText use following Code
<com.blackcat.currencyedittext.CurrencyEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
check this link https://github.com/BlacKCaT27/CurrencyEditText
I want to separate automatically edit text like (9,99,999) like this. i searched for this on web but i am not getting proper solution for this.
can you please help me.thank you stack overflow.
You can use DecimalFormat for this like below Code:
public String formatNumber(double d) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
formatter.applyPattern("#,###");
return formatter.format(d);
}
You Can Pass Pattern as you want.
public static String formatCurrency(String number) {
try {
number = NumberFormat.getNumberInstance(Locale.US).format(Double.valueOf(number));
} catch (Exception e) {
}
return number;
}
This is what i did. Works perfectly
Try this.
public class NumberTextWatcherForThousand implements TextWatcher {
EditText editText;
public NumberTextWatcherForThousand(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 != null && !value.equals(""))
{
if(value.startsWith(".")){ //adds "0." when only "." is pressed on begining of writting
editText.setText("0.");
}
if(value.startsWith("0") && !value.startsWith("0.")){
editText.setText(""); //Prevents "0" while starting but not "0."
}
String str = editText.getText().toString().replaceAll(",", "");
if (!value.equals(""))
editText.setText(getDecimalFormat(str));
editText.setSelection(editText.getText().toString().length());
}
editText.addTextChangedListener(this);
return;
}
catch (Exception ex)
{
ex.printStackTrace();
editText.addTextChangedListener(this);
}
}
public static String getDecimalFormat(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++;
}
}
//Trims all the comma of the string and returns
public static String trimCommaOfString(String string) {
if(string.contains(",")){
return string.replace(",","");}
else {
return string;
}
}
}
editText.addTextChangedListener(new TextWatcher() {
#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 editable) {
editText.removeTextChangedListener(this);
try {
StringBuilder originalString = new StringBuilder(editable.toString().replaceAll(",", ""));
int indx = 0;
for (int i = originalString.length(); i > 0; i--) {
if (indx % 3 == 0 && indx > 0)
originalString = originalString.insert(i, ",");
indx++;
}
editText.setText(originalString);
editText.setSelection(originalString.length());
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
editText.addTextChangedListener(this);
}
});
I am writing a Convertor Application and I want a thousand separator automatically added to the digits in realtime, so after I implemented this applypattern code on the TextWatcher, now I can not make floationg point inputs.....here is my code for the Editext
am2 = new TextWatcher()
{
boolean isEdiging;
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) {
if (s.toString().equals("")) {
amount.setText("");
value = 0;
}else{
if(isEdiging) return;
isEdiging = true;
StringBuffer strBuff = new StringBuffer();
char c;
for (int i = 0; i < amount2.getText().toString().length() ; i++) {
c = amount2.getText().toString().charAt(i);
if (Character.isDigit(c)) {
strBuff.append(c);
}
}
value = Double.parseDouble(strBuff.toString());
reverse();
NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
((DecimalFormat)nf2).applyPattern("###,###.#######");
s.replace(0, s.length(), nf2.format(value));
isEdiging = false;
}
}
};
So is there any way of inputting floating point within the EditText?
This class solves the problem
public class NumberTextWatcher implements TextWatcher {
private DecimalFormat df;
private DecimalFormat dfnd;
private boolean hasFractionalPart;
private EditText et;
public NumberTextWatcher(EditText et)
{
df = new DecimalFormat("#,###.##");
df.setDecimalSeparatorAlwaysShown(true);
dfnd = new DecimalFormat("#,###");
this.et = et;
hasFractionalPart = false;
}
#SuppressWarnings("unused")
private static final String TAG = "NumberTextWatcher";
public void afterTextChanged(Editable s)
{
et.removeTextChangedListener(this);
try {
int inilen, endlen;
inilen = et.getText().length();
String v = s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()), "");
Number n = df.parse(v);
int cp = et.getSelectionStart();
if (hasFractionalPart) {
et.setText(df.format(n));
} else {
et.setText(dfnd.format(n));
}
endlen = et.getText().length();
int sel = (cp + (endlen - inilen));
if (sel > 0 && sel <= et.getText().length()) {
et.setSelection(sel);
} else {
// place cursor at the end?
et.setSelection(et.getText().length() - 1);
}
} catch (NumberFormatException nfe) {
// do nothing?
} catch (ParseException e) {
// do nothing?
}
et.addTextChangedListener(this);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
}
public void onTextChanged(CharSequence s, int start, int before, int count)
{
if (s.toString().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
{
hasFractionalPart = true;
} else {
hasFractionalPart = false;
}
}
}
I'm totally new to Android.
I would like to put in a textbox where user can enter an IP address ... but how do I limit the user to only enter numbers? ... and how do I validate?
Is there a ready-made-ip-address-textbox "out there" I can use?
Thanks!
Mojo
What I've found that works is to set an EditText to use android:inputType="phone", so the input is restricted to digits, period, and a handful of other characters. However, this will only let you input IPV4 addresses, since it's digits only. For validation, you'll have to get the input text and parse it by hand.
As far as ready-made input widgets, I haven't come across one.
In addition to what Erich said, you can use android:digits="0123456789." to disallow anything but digits and a decimal point.
You can use :
EditText ipAddress = (EditText)findViewById(R.id.ip_address);
InputFilter[] filters = new InputFilter[1];
filters[0] = new InputFilter() {
#Override
public CharSequence filter(CharSequence source, int start, int end,
android.text.Spanned dest, int dstart, int dend) {
if (end > start) {
String destTxt = dest.toString();
String resultingTxt = destTxt.substring(0, dstart) + source.subSequence(start, end) + destTxt.substring(dend);
if (!resultingTxt.matches ("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) {
return "";
} else {
String[] splits = resultingTxt.split("\\.");
for (int i=0; i<splits.length; i++) {
if (Integer.valueOf(splits[i]) > 255) {
return "";
}
}
}
}
return null;
}
};
ipAddress.setFilters(filters);
For validation, regular-expressions.info has a good regex string you could use for testing for an IP in a valid (0-255) range:
\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
This is, I think, the most complete of the existing solutions to this (at least that I've found). The only improvement I can imagine is to implement a new KeyListener to restrain the input better but I'm not convinced it is practically possible, given how IMEs work with layouts and stuff.
public class IPAddressText extends EditText {
public IPAddressText(Context context) {
super(context);
setInputType(InputType.TYPE_CLASS_PHONE);
setFilters(new InputFilter[] { new InputFilter(){
#Override
public CharSequence filter(CharSequence source, int start, int end, android.text.Spanned dest, int dstart, int dend) {
if (end > start) {
String destTxt = dest.toString();
String resultingTxt = destTxt.substring(0, dstart) + source.subSequence(start, end) + destTxt.substring(dend);
if (!resultingTxt.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) {
return "";
}
else {
String[] splits = resultingTxt.split("\\.");
for (int i = 0; i < splits.length; i++) {
if (Integer.valueOf(splits[i]) > 255) {
return "";
}
}
}
}
return null;
}
}
});
addTextChangedListener(new TextWatcher(){
boolean deleting = false;
int lastCount = 0;
#Override
public void afterTextChanged(Editable s) {
if (!deleting) {
String working = s.toString();
String[] split = working.split("\\.");
String string = split[split.length - 1];
if (string.length() == 3 || string.equalsIgnoreCase("0")
|| (string.length() == 2 && Character.getNumericValue(string.charAt(0)) > 1)) {
s.append('.');
return;
}
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (lastCount < count) {
deleting = false;
}
else {
deleting = true;
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Nothing happens here
}
});
}
}
And because it is what I actually ended up using, here is an EditTextPreference version:
public class IPAddressPreference extends EditTextPreference {
public IPAddressPreference(Context context) {
super(context);
getEditText().setInputType(InputType.TYPE_CLASS_PHONE);
getEditText().setFilters(new InputFilter[] { new InputFilter(){
#Override
public CharSequence filter(CharSequence source, int start, int end, android.text.Spanned dest, int dstart, int dend) {
if (end > start) {
String destTxt = dest.toString();
String resultingTxt = destTxt.substring(0, dstart) + source.subSequence(start, end) + destTxt.substring(dend);
if (!resultingTxt.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) {
return "";
}
else {
String[] splits = resultingTxt.split("\\.");
for (int i = 0; i < splits.length; i++) {
if (Integer.valueOf(splits[i]) > 255) {
return "";
}
}
}
}
return null;
}
}
});
getEditText().addTextChangedListener(new TextWatcher(){
boolean deleting = false;
int lastCount = 0;
#Override
public void afterTextChanged(Editable s) {
if (!deleting) {
String working = s.toString();
String[] split = working.split("\\.");
String string = split[split.length - 1];
if (string.length() == 3 || string.equalsIgnoreCase("0")
|| (string.length() == 2 && Character.getNumericValue(string.charAt(0)) > 1)) {
s.append('.');
return;
}
}
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (lastCount < count) {
deleting = false;
}
else {
deleting = true;
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Nothing happens here
}
});
}
}
I'm using this TextWatcher:
public class IPTextWatcher implements TextWatcher
{
private static String LOG_TAG = "IPTextWatcher";
private EditText editText;
private BarcodeTextWatcher.ChangeListener listener = null;
public IPTextWatcher( EditText editText )
{
this.editText = editText;
}
private static final String IPADDRESS_PATTERN =
"^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
"([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
#Override
public void afterTextChanged( Editable s )
{
Log.v( LOG_TAG, s.toString() );
if( !s.toString().matches( IPADDRESS_PATTERN ) )
{
String ip = format( s.toString() );
editText.removeTextChangedListener( this );
editText.setText( ip );
editText.setTextKeepState( ip );
Selection.setSelection( editText.getText(), ip.length() );
editText.addTextChangedListener( this );
if( listener != null )
listener.onChange();
}
}
public static String format( String value )
{
String userInput = "" + value.replaceAll( "[^\\d\\.]", "" );
StringBuilder ipBuilder = new StringBuilder();
String[] address = userInput.split("\\.");
String glue = null;
for( String part : address )
{
if( glue != null ) ipBuilder.append( glue );
int p = Integer.valueOf( part );
if( p >= 256 )
{
int i = 1;
do
{
p = Integer.valueOf( part.substring( 0, part.length() -i ) );
i++;
}
while( p >= 256 );
}
ipBuilder.append( p );
glue = ".";
}
if( userInput.charAt( userInput.length()-1 ) == '.' )
ipBuilder.append( "." );
return ipBuilder.toString();
}
#Override
public void onTextChanged( CharSequence s, int start, int before, int count )
{
}
#Override
public void beforeTextChanged( CharSequence s, int start, int count, int after )
{
}
}
<EditText
android:id="#+id/ip_address"
android:inputType="number|numberDecimal"
android:digits="0123456789."
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
worked for me
Based on NathanOliver's and enneract's code I wrote, in kotlin, a variation that insertes a dot when one is deleted.
class IpAddressEditText : AppCompatEditText {
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
private fun init() {
// phone input type to show the numeric keyboard in all kinds of devices
inputType = InputType.TYPE_CLASS_PHONE
// restrict the input of the characters specified in string bellow
keyListener = DigitsKeyListener.getInstance("0123456789.")
// InputFilter decides what can be typed
filters = arrayOf(InputFilter { source, start, end, dest, dstart, dend ->
if (end > start) {
val inputString = dest.toString()
val substring = inputString.substring(0, dstart) + source.subSequence(start, end) + inputString.substring(dend)
if (!substring.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?".toRegex())) {
// do not allow the input of:
// segments with more than 3 characters and less than 1;
// segments != 4;
return#InputFilter ""
} else {
val splits = substring.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (i in splits.indices) {
// don't allow a segment with a value more than 255
if (Integer.valueOf(splits[i]) > 255) {
return#InputFilter ""
}
}
}
}
null
})
// TextWatcher notifies what was typed
addTextChangedListener(object : TextWatcher {
var isDeleting = false
var lastCount = 0
override fun afterTextChanged(editable: Editable) {
if (!isDeleting) {
val inputString = editable.toString()
val segmentList = inputString.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val lastSegment = segmentList[segmentList.size - 1]
// each segment of the ip can have max size of 3 characters and a max value of 255
if (lastSegment.length == 3 || lastSegment.length == 2 && Integer.parseInt(lastSegment) > 25) {
// add a dot automatically if the conditions met
editable.append('.')
return
}
} else {
// add a dot in the same position where it was deleted
editable.insert(selectionStart, ".")
}
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
isDeleting = lastCount >= count
}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// do nothing
}
})
}
}
Here is the code that limits a user to only enter numbers and dots by displaying a soft keyboard with only numbers and a dot (but allows you to enter multiple dots).
etIpAddress.setInputType(InputType.TYPE_CLASS_NUMBER);
etIpAddress.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
etIpAddress.setKeyListener(DigitsKeyListener.getInstance(false,false));
etIpAddress.setKeyListener(DigitsKeyListener.getInstance("0123456789."));