如何自动添加千个分隔符作为编辑文本中的数字输入

我创建一个转换器应用程序。我想设置 EditText,这样当用户输入要转换的数字时,一旦数字增加3位数: 千、百万、十亿等,就应该实时自动添加1000个分隔符(,)。
当被擦除到4位数以下时,数字恢复正常。
有人帮忙吗?

90457 次浏览

可以在 TextWatcher.格式说明符中的逗号起到了这个作用。中使用 String.format()

这对于浮点输入不起作用。并且注意不要用 TextWatcher 设置无限循环。

public void afterTextChanged(Editable view) {
String s = null;
try {
// The comma in the format specifier does the trick
s = String.format("%,d", Long.parseLong(view.toString()));
} catch (NumberFormatException e) {
}
// Set s back to the view after temporarily removing the text change listener
}

因为我也有同样的问题,所以我决定找到一个解决办法

找到我的功能下面我希望它能帮助人们找到解决方案

securityDeposit.addTextChangedListener(new TextWatcher() {


@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
// TODO Auto-generated method stub


}


@Override
public void beforeTextChanged(CharSequence s, int start,
int before, int count) {
// TODO Auto-generated method stub


}


@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
if (s.toString().trim().length() > 0) {
int rentValue = Integer.parseInt(s.toString()
.replaceAll(",", ""));
StringBuffer rentVal = new StringBuffer();
if (rentValue > 10000000) {
s.clear();
s.append("10,000,000");
} else {


if (s.length() == 4) {
char x[] = s.toString().toCharArray();


char y[] = new char[x.length + 1];
for (int z = 0; z < y.length; z++) {


if (z == 1) {
y[1] = ',';


} else {
if (z == 0)
y[z] = x[z];
else {
y[z] = x[z - 1];
}
}


}


for (int z = 0; z < y.length; z++) {
rentVal = rentVal.append(y[z]);
}


s.clear();
s.append(rentVal);


}


}
}


}
});
public static String doubleToStringNoDecimal(double d) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
formatter.applyPattern("#,###");
return formatter.format(d);
}

虽然已经很晚了,是给未来的访客准备的。

下列代码的特性

  1. 当文本变化时,在 EditText中放置千分隔符。

  2. 当按下句点(。)时,首先自动添加 0.

  3. 开始时忽略 0输入。

只要复制以下内容 类名为

编号 TextWatcherForMillennium 其中 工具 < strong > TextWatcher

import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import java.util.StringTokenizer;


/**
* Created by skb on 12/14/2015.
*/
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) {
//        String returnString;
if(string.contains(",")){
return string.replace(",","");}
else {
return string;
}


}
}

EditText上使用这个类,如下所示

editText.addTextChangedListener(new NumberTextWatcherForThousand(editText));

以纯双文本形式获取输入

像下面这样使用同一个类的 trimCommaOfString方法

NumberTextWatcherForThousand.trimCommaOfString(editText.getText().toString())

饭桶

你可以在程序中以多种方式使用这段代码,你给它一个字符串,它把每个字符串从右边分开,并在那里放置空格。

private String Spacer(String number){
StringBuilder strB = new StringBuilder();
strB.append(number);
int Three = 0;


for(int i=number.length();i>0;i--){
Three++;
if(Three == 3){
strB.insert(i-1, " ");
Three = 0;
}
}
return strB.toString();
}// end Spacer()

你可以稍微修改一下,在 textchangelistener 上使用它。 祝你好运

这个 示例应用程序清楚地解构了格式化数字。

为了总结上面的链接,使用 TextWatcherafterTextChanged()方法格式的 EditText视图,其逻辑如下:

@Override
public void afterTextChanged(Editable s) {
editText.removeTextChangedListener(this);


try {
String originalString = s.toString();


Long longval;
if (originalString.contains(",")) {
originalString = originalString.replaceAll(",", "");
}
longval = Long.parseLong(originalString);


DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
formatter.applyPattern("#,###,###,###");
String formattedString = formatter.format(longval);


//setting text after format to EditText
editText.setText(formattedString);
editText.setSelection(editText.getText().length());
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}


editText.addTextChangedListener(this);
}

这个解决方案比其他解决方案有一些优势。例如,即使用户编辑数字的开头或中间,它也会保留用户的光标位置。其他解决方案总是将光标跳到数字的末尾.它处理 小数和整数,以及使用除小数点 .以外的字符的地区,以及使用数千个分组分隔符的地区。

class SeparateThousands(val groupingSeparator: String, val decimalSeparator: String) : TextWatcher {


private var busy = false


override fun afterTextChanged(s: Editable?) {
if (s != null && !busy) {
busy = true


var place = 0


val decimalPointIndex = s.indexOf(decimalSeparator)
var i = if (decimalPointIndex == -1) {
s.length - 1
} else {
decimalPointIndex - 1
}
while (i >= 0) {
val c = s[i]
if (c == groupingSeparator[0] ) {
s.delete(i, i + 1)
} else {
if (place % 3 == 0 && place != 0) {
// insert a comma to the left of every 3rd digit (counting from right to
// left) unless it's the leftmost digit
s.insert(i + 1, groupingSeparator)
}
place++
}
i--
}


busy = false
}
}


override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}


override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
}

然后在 xml 中:

  <EditText
android:id="@+id/myNumberField"
android:digits=",.0123456789"
android:inputType="numberDecimal"
.../>

最后注意观察者:

findViewById(R.id.myNumberField).addTextChangedListener(
SeparateThousands(groupingSeparator, decimalSeparator))

要处理. vs,在不同的地区使用 groupingPartiator 和 decimalPartiator,它们可以来自 DecimalFormatSymbols 或本地化字符串。

这是我的 ThousandNumberEditText课程

public class ThousandNumberEditText extends android.support.v7.widget.AppCompatEditText {
// TODO: 14/09/2017 change it if you want
private static final int MAX_LENGTH = 20;
private static final int MAX_DECIMAL = 3;


public ThousandNumberEditText(Context context) {
this(context, null);
}


public ThousandNumberEditText(Context context, AttributeSet attrs) {
this(context, attrs, android.support.v7.appcompat.R.attr.editTextStyle);
}


public ThousandNumberEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}


private void init() {
addTextChangedListener(new ThousandNumberTextWatcher(this));
setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
setFilters(new InputFilter[] { new InputFilter.LengthFilter(MAX_LENGTH) });
setHint("0"); // TODO: 14/09/2017 change it if you want
}


private static class ThousandNumberTextWatcher implements TextWatcher {


private EditText mEditText;


ThousandNumberTextWatcher(EditText editText) {
mEditText = 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) {
String originalString = editable.toString();
String cleanString = originalString.replaceAll("[,]", "");
if (cleanString.isEmpty()) {
return;
}
String formattedString = getFormatString(cleanString);


mEditText.removeTextChangedListener(this);
mEditText.setText(formattedString);
mEditText.setSelection(mEditText.getText().length());
mEditText.addTextChangedListener(this);
}


/**
* Return the format string
*/
private String getFormatString(String cleanString) {
if (cleanString.contains(".")) {
return formatDecimal(cleanString);
} else {
return formatInteger(cleanString);
}
}


private String formatInteger(String str) {
BigDecimal parsed = new BigDecimal(str);
DecimalFormat formatter;
formatter = new DecimalFormat("#,###");
return formatter.format(parsed);
}


private String formatDecimal(String str) {
if (str.equals(".")) {
return ".";
}
BigDecimal parsed = new BigDecimal(str);
DecimalFormat formatter;
formatter =
new DecimalFormat("#,###." + getDecimalPattern(str)); //example patter #,###.00
return formatter.format(parsed);
}


/**
* It will return suitable pattern for format decimal
* For example: 10.2 -> return 0 | 10.23 -> return 00 | 10.235 -> return 000
*/
private String getDecimalPattern(String str) {
int decimalCount = str.length() - 1 - str.indexOf(".");
StringBuilder decimalPattern = new StringBuilder();
for (int i = 0; i < decimalCount && i < MAX_DECIMAL; i++) {
decimalPattern.append("0");
}
return decimalPattern.toString();
}
}
}

吸毒

<.ThousandNumberEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>

我知道我已经迟到了,但这对未来的用户可能非常有用。我的答案是 Shree Krishna答案的延伸。

改善措施:

  1. 数以千计的分隔符和十进制标记是可识别的,也就是说,它们是根据设备的 Locale来使用的。
  2. 在删除或添加中间的元素后,光标的位置也不会改变(在他的回答中,光标被重置为末尾)。
  3. 特别是采用 getDecimalFormattedString方法提高了代码的整体质量。

密码:

    import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;


import java.text.DecimalFormat;




/**
* Created by srv_twry on 4/12/17.
* Source: https://stackoverflow.com/a/34265406/137744
* The custom TextWatcher that automatically adds thousand separators in EditText.
*/


public class ThousandSeparatorTextWatcher implements TextWatcher {


private DecimalFormat df;
private EditText editText;
private static String thousandSeparator;
private static String decimalMarker;
private int cursorPosition;


public ThousandSeparatorTextWatcher(EditText editText) {
this.editText = editText;
df = new DecimalFormat("#,###.##");
df.setDecimalSeparatorAlwaysShown(true);
thousandSeparator = Character.toString(df.getDecimalFormatSymbols().getGroupingSeparator());
decimalMarker = Character.toString(df.getDecimalFormatSymbols().getDecimalSeparator());
}


@Override
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
cursorPosition = editText.getText().toString().length() - editText.getSelectionStart();
}


@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}


@Override
public void afterTextChanged(Editable s) {
try {
editText.removeTextChangedListener(this);
String value = editText.getText().toString();


if (value != null && !value.equals("")) {
if (value.startsWith(decimalMarker)) {
String text = "0" + decimalMarker;
editText.setText(text);
}
if (value.startsWith("0") && !value.startsWith("0" + decimalMarker)) {
int index = 0;
while (index < value.length() && value.charAt(index) == '0') {
index++;
}
String newValue = Character.toString(value.charAt(0));
if (index != 0) {
newValue = value.charAt(0) + value.substring(index);
}
editText.setText(newValue);
}
String str = editText.getText().toString().replaceAll(thousandSeparator, "");
if (!value.equals("")) {
editText.setText(getDecimalFormattedString(str));
}
editText.setSelection(editText.getText().toString().length());
}


//setting the cursor back to where it was
editText.setSelection(editText.getText().toString().length() - cursorPosition);
editText.addTextChangedListener(this);
} catch (Exception ex) {
ex.printStackTrace();
editText.addTextChangedListener(this);
}
}


private static String getDecimalFormattedString(String value) {


String[] splitValue = value.split("\\.");
String beforeDecimal = value;
String afterDecimal = null;
String finalResult = "";


if (splitValue.length == 2) {
beforeDecimal = splitValue[0];
afterDecimal = splitValue[1];
}


int count = 0;
for (int i = beforeDecimal.length() - 1; i >= 0 ; i--) {
finalResult = beforeDecimal.charAt(i) + finalResult;
count++;
if (count == 3 && i > 0) {
finalResult = thousandSeparator + finalResult;
count = 0;
}
}


if (afterDecimal != null) {
finalResult = finalResult + decimalMarker + afterDecimal;
}


return finalResult;
}


/*
* Returns the string after removing all the thousands separators.
* */
public static String getOriginalString(String string) {
return string.replace(thousandSeparator,"");
}
}

我只是想把 comma放在这里,这对我很有效:

String.format("%,.2f", myValue);

你可以使用这个方法:

myEditText.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) {


String input = s.toString();


if (!input.isEmpty()) {


input = input.replace(",", "");


DecimalFormat format = new DecimalFormat("#,###,###");
String newPrice = format.format(Double.parseDouble(input));




myEditText.removeTextChangedListener(this); //To Prevent from Infinite Loop


myEditText.setText(newPrice);
myEditText.setSelection(newPrice.length()); //Move Cursor to end of String


myEditText.addTextChangedListener(this);
}


}


@Override
public void afterTextChanged(final Editable s) {
}
});

要获得原始文本,请使用以下内容:

String input = myEditText.getText().toString();
input = input.replace(",", "");

这里的答案缺乏处理实际用户输入的方法,比如删除字符或复制粘贴。这是一个 EditText 字段。如果要添加格式化,则需要支持编辑该格式化值。

这个实现仍然存在不足,这取决于您的用例。我不关心十进制值,假设我只处理整数。如何处理这个问题以及如何处理实际的国际化已经足够了,我将把它留给读者作为练习。如果你需要这样做,添加“应该不会太难。”转换为正则表达式以保留小数; 您只需要小心确认数字字符串仍然有非数字字符。

它被设计用于多个活动中。新建一次,给它编辑文本和数据模型,然后忽略它。如果不需要,可以删除模型绑定。

public class EditNumberFormatter implements TextWatcher {


private EditText watched;
private Object model;
private Field field;
private IEditNumberFormatterListener listener;


private ActiveEdit activeEdit;


/**
* Binds an EditText to a data model field (Such as a room entity's public variable)
* Whenever the edit text is changed, the text is formatted to the local numerical format.
*
* Handles copy/paste/backspace/select&delete/typing
*
* @param model An object with a public field to bind to
* @param fieldName A field defined on the object
* @param watched The edit text to watch for changes
* @param listener Another object that wants to know after changes & formatting are done.
*/
public EditNumberFormatter(Object model, String fieldName, EditText watched, IEditNumberFormatterListener listener) {


this.model = model;
this.watched = watched;
this.listener = listener;


try {
field = model.getClass().getDeclaredField(fieldName);
} catch(Exception e) { }


watched.addTextChangedListener(this);
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
activeEdit = new ActiveEdit(s.toString(), start, count);
}


@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
activeEdit.recordChangedText(s.toString(),count);
}


@Override
public void afterTextChanged(Editable s) {
this.watched.removeTextChangedListener(this);


activeEdit.processEdit(); // Override the user's edit of the formatted string with what the user intended to do to the numeral.


watched.setText(activeEdit.getCurrentFormattedString());
watched.setSelection(activeEdit.getCursorPosition());
updateDataModel(activeEdit.getCurrentRawValue());


listener.FormatUpdated(watched.getId(), activeEdit.getCurrentRawValue(), activeEdit.getCurrentFormattedString());


this.watched.addTextChangedListener(this);
}


private void updateDataModel(int rawValue) {
try {
field.set(model, rawValue);
} catch (IllegalAccessException e) { }
}


/**
* Tracks the active editing of an EditText formatted for integer input
*/
private class ActiveEdit {


private String priorFormattedString;
private String currentFormattedString;
private String currentNumericalString;
private int currentRawValue;


private boolean removal;
private boolean addition;


private int changeStart;
private int removedCount;
private int additionCount;


private int numeralCountBeforeSelection;
private int numeralCountAdded;
private int numeralCountRemoved;


/**
* Call in beforeEdit to begin recording changes
*
* @param beforeEdit string before edit began
* @param start start position of edit
* @param removed number of characters removed
*/
public ActiveEdit(String beforeEdit, int start, int removed) {
removal = (removed > 0);


priorFormattedString = beforeEdit;
changeStart = start;
removedCount = removed;


numeralCountBeforeSelection = countNumerals(priorFormattedString.substring(0, changeStart));
numeralCountRemoved = countNumerals(priorFormattedString.substring(changeStart, changeStart + removedCount));
}


/**
* Call in onTextChanged to record new text and how many characters were added after changeStart
*
* @param afterEdit new string after user input
* @param added how many characters were added (same start position as before)
*/
public void recordChangedText(String afterEdit, int added) {
addition = (added > 0);
additionCount = added;
numeralCountAdded = countNumerals(afterEdit.substring(changeStart, changeStart + additionCount));


currentNumericalString = afterEdit.replaceAll("[^0-9]", "");
}


/**
* Re-process the edit for our particular formatting needs.
*/
public void processEdit() {
forceRemovalPastFormatting();
finalizeEdit();
}


/**
* @return Integer value of the field after an edit.
*/
public int getCurrentRawValue() {
return currentRawValue;
}


/**
* @return Formatted number after an edit.
*/
public String getCurrentFormattedString() {
return currentFormattedString;
}


/**
* @return Cursor position after an edit
*/
public int getCursorPosition() {
int numeralPosition = numeralCountBeforeSelection + numeralCountAdded;
return positionAfterNumeralN(currentFormattedString,numeralPosition);
}


/**
* If a user deletes a value, but no numerals are deleted, then delete the numeral proceeding
* their cursor. Otherwise, we'll just add back the formatting character.
*
* Assumes formatting uses a single character and not multiple formatting characters in a row.
*/
private void forceRemovalPastFormatting() {
if (removal && (!addition) && (numeralCountRemoved == 0)) {
String before = currentNumericalString.substring(0, numeralCountBeforeSelection - 1);
String after = currentNumericalString.substring(numeralCountBeforeSelection);


currentNumericalString =  before + after;
numeralCountRemoved++;
numeralCountBeforeSelection--;
}
}


/**
* Determine the result of the edit, including new display value and raw value
*/
private void finalizeEdit() {
currentFormattedString = "";
currentRawValue = 0;
if (currentNumericalString.length() == 0) {
return; // There is no entry now.
}
try {
currentRawValue = Integer.parseInt(currentNumericalString);
} catch (NumberFormatException nfe) {
abortEdit();  // Value is not an integer, return to previous state.
return;
}
currentFormattedString = String.format("%,d", currentRawValue);
}


/**
* Current text, same as the old text.
*/
private void abortEdit() {
currentFormattedString = priorFormattedString;
currentNumericalString = currentFormattedString.replaceAll("[^0-9]", "");
numeralCountRemoved = 0;
numeralCountAdded = 0;
try {
currentRawValue = Integer.parseInt(currentNumericalString);
} catch (Exception e) { currentRawValue = 0; }
}


/**
* Determine how many numerical characters exist in a string
* @param s
* @return the number of numerical characters in the string
*/
private int countNumerals(String s) {
String newString = s.replaceAll("[^0-9]", "");
return newString.length();
}


/**
* Determine how to place a cursor after the Nth Numeral in a formatted string.
* @param s - Formatted string
* @param n - The position of the cursor should follow the "Nth" number in the string
* @return the position of the nth character in a formatted string
*/
private int positionAfterNumeralN(String s, int n) {
int numeralsFound = 0;


if (n == 0) {
return 0;
}


for (int i = 0; i < s.length(); i++) {
if(s.substring(i,i+1).matches("[0-9]")) {
if(++numeralsFound == n) {
return i + 1;
}
}
}
return s.length();
}
}
}

从高层来看,它的作用是:

  • 确定编辑后字符串中实际存在的数字
  • 如果数字未被编辑,则将编辑过程处理为字符串的数字版本
  • 将数字转换回带格式的字符串
  • 根据编辑开始的位置和添加的文本数量确定光标的位置

它还能很好地处理边缘情况,如完全删除的输入,整数溢出和错误的输入。

在这里我已经测试了我的应用程序代码。文本观察者如何添加逗号在货币千,湖泊货币。

 private TextWatcher textWatcherAmount = 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) {
String initial = s.toString();


if (inputEdtHawalaRate == null) return;


if (!TextUtils.isEmpty(initial)) {


initial = initial.replace(",", "");


NumberFormat formatter = new DecimalFormat("##,##,###");


inputEdtHawalaRate.removeTextChangedListener(this);


double myNumber = Double.parseDouble(initial);
String processed = formatter.format(myNumber);


//Assign processed text
inputEdtHawalaRate.setText(processed);


try {
inputEdtHawalaRate.setSelection(processed.length());
} catch (Exception e) {
e.printStackTrace();
}


//Give back the listener
inputEdtHawalaRate.addTextChangedListener(this);


}


}


@Override
public void afterTextChanged(Editable s) {


}
};




if (inputEdtHawalaRate != null) {
inputEdtHawalaRate.addTextChangedListener(textWatcherAmount);
}

//在双类型变量上获取金额(在 texttwatcher edetxt 值 get 上)。

String amount = Objects.requireNonNull(inputEdtHawalaRate.getText()).toString().trim();
double hawalaAmount = 0.0;


String[] a = amount.split(",");
finalAmount = TextUtils.join("", a);
hawalaAmount = Double.parseDouble(finalAmount);

您可以使用自定义 编辑文本:

public class NumberTextInputEditText extends TextInputEditText {


public NumberTextInputEditText(@NonNull Context context) {
super(context);
}


public NumberTextInputEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}


public NumberTextInputEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}


@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
addTextChangedListener(textWatcher);
}


public String formatNumber(double number) {
DecimalFormat decimalFormat = new DecimalFormat("#,###");
return decimalFormat.format(number);
}


public TextWatcher textWatcher = 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) {
removeTextChangedListener(this);
String text = getText().toString();
String format = "";
if (!TextUtils.isEmpty(text)) {
try {
format = formatNumber(Double.parseDouble(new BigDecimal(text.replaceAll(",", "")).toString()));
} catch (NumberFormatException e) {
format = "";
}
setText(format);
setSelection(format.length());
}
addTextChangedListener(this);
}
};}

就像你的布局中的视图一样使用它:

<com.your.package.name.NumberTextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

我正在寻找一个区域感知的解决方案,因为我们的客户遍布全球。所以我建立在 D0pdb的答案之上。

下面是我为解决这个问题而创建的 TextWatcher 类(在 kotlin 中)。

Https://github.com/abhilashd-locus/edittext-locale-aware-thousands-separator

特点:

  • 根据用户类型动态添加数千个分隔符
  • 允许在字符串之间进行编辑,而不仅仅是在字符串的末尾
  • 千分离的风格是基于场所的(例如: 100,000对1,00,000)
  • 数千个分隔符和小数标记的符号是基于区域设置的(例如: 100.000.00 vs 100.000.00)
  • 支持所有语言和地区

缺点:

  • 不支持复制/粘贴操作
  • 在从右向左的语言(例如阿拉伯语)中,当删除第一个数字时,光标会跳到末尾

.

// ThousandsSeparatorTextWatcher.kt --> add this TextWatcher to the
// EditText you want to add the functionality of dynamic locale aware thousands separator
class ThousandsSeparatorTextWatcher(private var editText: EditText?, private val callback: TextChangedCallback) : TextWatcher {


//keeping a count of the digits before the cursor to reset the cursor at the correct place
private var digitsBeforeCursor = -1
private val thousandSeparator: Char = DecimalFormatSymbols(Locale.getDefault()).groupingSeparator
private val decimalMarker: Char = DecimalFormatSymbols(Locale.getDefault()).decimalSeparator


init {
editText?.apply {


addTextChangedListener(this@ThousandsSeparatorTextWatcher)


//disabling copy/paste to avoid format and parse errors
disableTextSelection(this)


//diabling text selection
isLongClickable = false
setTextIsSelectable(false)


//ensuring correct input type
keyListener = DigitsKeyListener.getInstance("0123456789$decimalMarker");
}
}


private fun disableTextSelection(editText: EditText) {


editText.customSelectionActionModeCallback = object : android.view.ActionMode.Callback {


override fun onActionItemClicked(mode: android.view.ActionMode?, item: MenuItem?) = false


override fun onCreateActionMode(mode: android.view.ActionMode?, menu: Menu?) = false


override fun onPrepareActionMode(mode: android.view.ActionMode?, menu: Menu?) = false


override fun onDestroyActionMode(mode: android.view.ActionMode?) {}
}
}


/***
* We are going to calculate the number of numeric digits before the cursor when user starts editing
* We will keep a count of this number to reset the cursor to the correct position after editing is complete
*/
override fun beforeTextChanged(sequenceBeforeEdit: CharSequence, startPos: Int, count: Int, after: Int) {


val textBeforeEdit = sequenceBeforeEdit.toString()


if (textBeforeEdit.isEmpty()) {
//in an empty string, cursor position is at 1 if a character is being added (after == 1)
//if a character is not being added, cursor position remains at the beginning
digitsBeforeCursor = if (after == 0) -1 else 1
return
}


digitsBeforeCursor = if (after == 0) {
//if characters are being removed
//count will always be 1 since we have disabled selection (in which case count will be equal to the number of characters selected)
val textBeforeNewCursor = textBeforeEdit.substring(0, startPos)
textBeforeNewCursor.count { it != thousandSeparator }
} else {
//if characters are being added
//after will always be 1 since we have disabled pasting (in which case after will be equal to the number of characters being pasted)
if (startPos == textBeforeEdit.length) {
//if adding a character to the end of the string
textBeforeEdit.count { it != thousandSeparator } + 1
} else {
//if adding a character in between the string
val textBeforeNewCursor = textBeforeEdit.substring(0, startPos + 1)
textBeforeNewCursor.count { it != thousandSeparator }
}
}
}


override fun onTextChanged(textAfterEdit: CharSequence, start: Int, before: Int, count: Int) {}


/***
* We will get the numeric value in the editText after stripping all the formatting
* We will then reformat this number to add the correct thousands separation and decimal marker according to the locale
* We then set the cursor to the correct position as we calculated in beforeTextChanged()
*/
override fun afterTextChanged(editable: Editable) {


val text = editable.toString()


//if the EditText is cleared, trigger callback with a null value to indicate an empty field
if (text.isEmpty()) {
digitsBeforeCursor = -1
callback.onChanged(null)
return
}


//get the double value of the entered number
val numberValue = getNumberFromFormattedCurrencyText(text)


//re-format the number to get the correct separation format and symbols
var newText = getCurrencyFormattedAmountValue(numberValue)


//If user was inputting decimal part of the number, reformatting will return a string without decimal point.
//So we need to add it back after the reformatting is complete
if (text.endsWith(decimalMarker)) {
newText += decimalMarker
} else if (text.endsWith(decimalMarker + "0")) {
newText += decimalMarker + "0"
}


//removing the listener to prevent infinite triggers
editText?.removeTextChangedListener(this)


//set the reformatted text
editText?.setText(newText)


//send the number typed to the callback
callback.onChanged(numberValue)


//set the cursor to the right position after reformatting the string
if (digitsBeforeCursor != -1) {
var numbersParsed = 0
for (i in newText.indices) {
if (newText[i] != thousandSeparator) {
numbersParsed++
}
if (numbersParsed == digitsBeforeCursor) {
editText?.setSelection(i + 1)
break
}
}
digitsBeforeCursor = -1
}


//add the listener back
editText?.addTextChangedListener(this)
}


/***
* Function to remove the listener and release reference to the EditText
*/
fun removeWatcherFromEditText() {
editText?.removeTextChangedListener(this)
editText = null
}


interface TextChangedCallback {
fun onChanged(newNumber: Double?)
}


companion object{
    

@JvmStatic
fun getNumberFromFormattedCurrencyText(formattedText: String?) = formattedText?.let {
val numberFormat = NumberFormat.getNumberInstance(Locale.getDefault())
try {
numberFormat.parse(it)?.toDouble()
} catch (exception: ParseException) {
0.0
}
} ?: 0.0


@JvmStatic
fun getCurrencyFormattedAmountValue(amount: Double?) = amount?.let {
val numberFormat = NumberFormat.getNumberInstance(Locale.getDefault())
numberFormat.maximumFractionDigits = 2
numberFormat.format(amount)
} ?: ""
}
}

我知道现在很晚了,但也许能帮上忙

fun generate_seprators(input: String?): String? {
var input = input
var result = ""
var float_section = ""
if (input == null) input = ""
var temp = input.trim { it <= ' ' }
temp = temp.replace(",", "")
var input_array = temp.split(".")
var decimal_section = input_array[0]
if(input_array.size>1)
float_section = input_array[1]
if (decimal_section.length > 3) {
var num = 0
for (i in decimal_section.length downTo 1) {
if (num == 3) {
num = 0
result = ",$result"
}
num++
result = decimal_section.substring(i - 1, i) + result
}
if(float_section!="")
result = "$result.$float_section"
} else {
result = decimal_section.replace(",", "")
if(float_section!="")
result = "$result.$float_section"
}
return result
}