我创建一个转换器应用程序,我想设置EditText,以便当用户输入要转换的数字时,一旦它增加3个数字,就应该实时自动添加一千个分隔符(,)....千万,百万,十亿等,当删除到4以下数字时,这个数字会恢复正常。有帮助吗?谢谢。
你可以在String.format()
中使用TextWatcher
。格式说明符中的逗号可以解决问题。
这不适用于浮点输入。并注意不要使用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);
}
}
}
}
});
我只是想放置comma
,这对我有用:
String.format("%,.2f", myValue);
这里的答案缺少处理实际用户输入的方法,例如删除字符或复制和粘贴。这是一个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();
}
}
}
从高层次来看,它的作用是:
它还可以很好地处理完全删除的输入,整数溢出和错误输入等边缘情况。
最后解决了这个问题
虽然答案太晚了。我已经研究了很多来完成任务以获得正确的结果,但却无法完成。所以我终于解决了我们正在搜索的问题,并向谷歌搜索者提供了这个答案,以节省他们的搜索时间。
以下代码的功能
EditText
中放入千分隔符。0.
。0
输入。只需复制以下命名的类
NumberTextWatcherForThousand实现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())
public static String doubleToStringNoDecimal(double d) {
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);;
formatter .applyPattern("#,###");
return formatter.format(d);
}
这个sample app清楚地解构格式化数字。
要总结上面的链接,请使用TextWatcher
并使用afterTextChanged()
方法格式化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 == ',') {
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,在不同的语言环境中使用groupingSeparator和decimalSeparator,它们可以来自DecimalFormatSymbols或本地化字符串。
我知道我参加聚会很晚,但对未来的用户来说可能非常有用。我的回答是Shree Krishna答案的延伸。
改进:
Locale
。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,"");
}
}
你可以在你的程序中以多种方式使用这段代码,你给它一个字符串,它将每三个与右边分开,并在那里放置空间。
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()
你可以改变它并使用它ontextchangelistener。祝好运
这是我的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"
/>
您可以使用此方法:
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(",", "");