更好的方式来格式货币输入editText?

我有一个editText,起始值是$ 0.00。 当您按1时,它将更改为$ 0.01。 按4,到$ 0.14。 按8,$ 1.48。 按退格键,$ 0.14等

这是有效的,问题是,如果有人手动定位光标,格式化会出现问题。 如果他们要删除小数,它不会回来。 如果他们把光标放在小数点前面并输入2,它将显示$ 02.00而不是$ 2.00。 如果他们试图删除$,它将删除一个数字,例如。

这里是我正在使用的代码,我会很感激任何建议。

mEditPrice.setRawInputType(Configuration.KEYBOARD_12KEY); public void priceClick(View view) { mEditPrice.addTextChangedListener(new TextWatcher(){ DecimalFormat dec = new DecimalFormat("0.00"); @Override public void afterTextChanged(Editable arg0) { } @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().matches("^\\$(\\d{1,3}(\\,\\d{3})*|(\\d+))(\\.\\d{2})?$")) { String userInput= ""+s.toString().replaceAll("[^\\d]", ""); if (userInput.length() > 0) { Float in=Float.parseFloat(userInput); float percen = in/100; mEditPrice.setText("$"+dec.format(percen)); mEditPrice.setSelection(mEditPrice.getText().length()); } } } }); 

我测试了你的方法,但是当我使用很多数字的时候失败了…我创建了这个:

 private String current = ""; @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if(!s.toString().equals(current)){ [your_edittext].removeTextChangedListener(this); String cleanString = s.toString().replaceAll("[$,.]", ""); double parsed = Double.parseDouble(cleanString); String formatted = NumberFormat.getCurrencyInstance().format((parsed/100)); current = formatted; [your_edittext].setText(formatted); [your_edittext].setSelection(formatted.length()); [your_edittext].addTextChangedListener(this); } } 

根据上面的一些答案,我创建了一个您将使用的MoneyTextWatcher,如下所示:

 priceEditText.addTextChangedListener(new MoneyTextWatcher(priceEditText)); 

这里是班级:

 public class MoneyTextWatcher implements TextWatcher { private final WeakReference<EditText> editTextWeakReference; public MoneyTextWatcher(EditText editText) { editTextWeakReference = new WeakReference<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 editable) { EditText editText = editTextWeakReference.get(); if (editText == null) return; String s = editable.toString(); editText.removeTextChangedListener(this); String cleanString = s.toString().replaceAll("[$,.]", ""); BigDecimal parsed = new BigDecimal(cleanString).setScale(2, BigDecimal.ROUND_FLOOR).divide(new BigDecimal(100), BigDecimal.ROUND_FLOOR); String formatted = NumberFormat.getCurrencyInstance().format(parsed); editText.setText(formatted); editText.setSelection(formatted.length()); editText.addTextChangedListener(this); } } 

实际上,之前提供的解决方案不起作用。 如果您想输入100.00,则不起作用。

更换:

 double parsed = Double.parseDouble(cleanString); String formato = NumberFormat.getCurrencyInstance().format((parsed/100)); 

附:

 BigDecimal parsed = new BigDecimal(cleanString).setScale(2,BigDecimal.ROUND_FLOOR).divide(new BigDecimal(100),BigDecimal.ROUND_FLOOR); String formato = NumberFormat.getCurrencyInstance().format(parsed); 

我必须说,我对我的代码做了一些修改。 问题是你应该使用BigDecimal的

使用TextWatcher更改类以使用Brasil货币格式并在编辑值时调整光标位置。

公共类MoneyTextWatcher实现TextWatcher {

    私人EditText editText;

     private String lastAmount =“”;

     private int lastCursorPosition = -1;

    公共MoneyTextWatcher(EditText editText){
        超();
         this.editText = editText;
     }

     @覆盖
    公共无效onTextChanged(CharSequence量,INT开始,诠释前,诠释计数){

         if(!amount.toString()。equals(lastAmount)){

             String cleanString = clearCurrencyToNumber(amount.toString());

            尝试{

                 String formattedAmount = transformToCurrency(cleanString);
                 editText.removeTextChangedListener(本);
                 editText.setText(formattedAmount);
                 editText.setSelection(formattedAmount.length());
                 editText.addTextChangedListener(本);

                 if(lastCursorPosition!= lastAmount.length()&& lastCursorPosition!= -1){
                     int lengthDelta = formattedAmount.length() -  lastAmount.length();
                     int newCursorOffset = max(0,min(formattedAmount.length(),lastCursorPosition + lengthDelta));
                     editText.setSelection(newCursorOffset);
                 }
             catch(Exception e){
                //记录一些东西
             }
         }
     }

     @覆盖
     public void afterTextChanged(Editable s){
     }

     @覆盖
     public void beforeTextChanged(CharSequence s,int start,int count,int after){
         String value = s.toString();
        如果(!value.equals( “”)){
             String cleanString = clearCurrencyToNumber(value);
             String formattedAmount = transformToCurrency(cleanString);
             lastAmount = formattedAmount;
             lastCursorPosition = editText.getSelectionStart();
         }
     }

     public static String clearCurrencyToNumber(String currencyValue){
         String result = null;

         if(currencyValue == null){
            结果=“”;
         } else {
             result = currencyValue.replaceAll(“[(az)|(AZ)|($ ,.)]”,“”);
         }
        返回结果;
     }

     public static boolean isCurrencyValue(String currencyValue,boolean podeSerZero){
        布尔结果

         if(currencyValue == null || currencyValue.length()== 0){
            结果= false;
         } else {
             if(!podeSerZero && currencyValue.equals(“0,00”)){
                结果= false;
             } else {
                结果= true;
             }
         }
        返回结果;
     }

     public static String transformToCurrency(String value){
         double parsed = Double.parseDouble(value);
         String formatted = NumberFormat.getCurrencyInstance(new Locale(“pt”,“BR”))。format((parsed / 100));
         formatted = formatted.replaceAll(“[^(0-9)(。,)]”,“”);
        返回格式化;
     }
 }

我建立在Guilhermes的答案上,但我保留了光标的位置,并以不同的方式处理期间 – 这样,如果用户在该期间后打字,它不会影响数字之前,我发现这会给一个非常流畅的输入。

  [yourtextfield].addTextChangedListener(new TextWatcher() { NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(); private String current = ""; @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if(!s.toString().equals(current)) { [yourtextfield].removeTextChangedListener(this); int selection = [yourtextfield].getSelectionStart(); // We strip off the currency symbol String replaceable = String.format("[%s,\\s]", NumberFormat.getCurrencyInstance().getCurrency().getSymbol()); String cleanString = s.toString().replaceAll(replaceable, ""); double price; // Parse the string try { price = Double.parseDouble(cleanString); } catch(java.lang.NumberFormatException e) { price = 0; } // If we don't see a decimal, then the user must have deleted it. // In that case, the number must be divided by 100, otherwise 1 int shrink = 1; if(!(s.toString().contains("."))) { shrink = 100; } // Reformat the number String formated = currencyFormat.format((price / shrink)); current = formated; [yourtextfield].setText(formated); [yourtextfield].setSelection(Math.min(selection, [yourtextfield].getText().length())); [yourtextfield].addTextChangedListener(this); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); 

好的,这里有一个更好的方式来处理货币格式,删除 – 向后的击键。 代码基于上面的@androidcurious代码…但是,处理一些与向后删除和一些解析异常相关的问题: http : //miguelt.blogspot.ca/2013/01/textwatcher-for-currency-masksformatting .html [更新]以前的解决方案有一些问题…这是一个更好的解决方案: http ://miguelt.blogspot.ca/2013/02/update-textwatcher-for-currency.html和…这里是细节:

这种方法更好,因为它使用传统的Android机制。 这个想法是在用户存在View之后格式化值。

定义一个InputFilter来限制数值 – 这在大多数情况下是必需的,因为屏幕不够大,无法容纳长的EditText视图。 这可以是一个静态的内部类或只是另一个普通类:

 /** Numeric range Filter. */ class NumericRangeFilter implements InputFilter { /** Maximum value. */ private final double maximum; /** Minimum value. */ private final double minimum; /** Creates a new filter between 0.00 and 999,999.99. */ NumericRangeFilter() { this(0.00, 999999.99); } /** Creates a new filter. * @param p_min Minimum value. * @param p_max Maximum value. */ NumericRangeFilter(double p_min, double p_max) { maximum = p_max; minimum = p_min; } @Override public CharSequence filter( CharSequence p_source, int p_start, int p_end, Spanned p_dest, int p_dstart, int p_dend ) { try { String v_valueStr = p_dest.toString().concat(p_source.toString()); double v_value = Double.parseDouble(v_valueStr); if (v_value<=maximum && v_value>=minimum) { // Returning null will make the EditText to accept more values. return null; } } catch (NumberFormatException p_ex) { // do nothing } // Value is out of range - return empty string. return ""; } } 

定义一个将实现View.OnFocusChangeListener的类(内部静态或只是一个类)。 请注意,我正在使用Utils类 – 实现可以在“金额,税收”中找到。

 /** Used to format the amount views. */ class AmountOnFocusChangeListener implements View.OnFocusChangeListener { @Override public void onFocusChange(View p_view, boolean p_hasFocus) { // This listener will be attached to any view containing amounts. EditText v_amountView = (EditText)p_view; if (p_hasFocus) { // v_value is using a currency mask - transfor over to cents. String v_value = v_amountView.getText().toString(); int v_cents = Utils.parseAmountToCents(v_value); // Now, format cents to an amount (without currency mask) v_value = Utils.formatCentsToAmount(v_cents); v_amountView.setText(v_value); // Select all so the user can overwrite the entire amount in one shot. v_amountView.selectAll(); } else { // v_value is not using a currency mask - transfor over to cents. String v_value = v_amountView.getText().toString(); int v_cents = Utils.parseAmountToCents(v_value); // Now, format cents to an amount (with currency mask) v_value = Utils.formatCentsToCurrency(v_cents); v_amountView.setText(v_value); } } } 

这个类将在编辑时删除货币格式 – 依靠标准机制。 当用户退出时,货币格式被重新应用。

最好定义一些静态变量来最小化实例的数量:

  static final InputFilter[] FILTERS = new InputFilter[] {new NumericRangeFilter()}; static final View.OnFocusChangeListener ON_FOCUS = new AmountOnFocusChangeListener(); 

最后,在onCreateView(…)中:

  EditText mAmountView = .... mAmountView.setFilters(FILTERS); mAmountView.setOnFocusChangeListener(ON_FOCUS); 

您可以在任意数量的EditText视图上重复使用FILTERS和ON_FOCUS。

这是Utils类:

 pubic class Utils { private static final NumberFormat FORMAT_CURRENCY = NumberFormat.getCurrencyInstance(); /** Parses an amount into cents. * @param p_value Amount formatted using the default currency. * @return Value as cents. */ public static int parseAmountToCents(String p_value) { try { Number v_value = FORMAT_CURRENCY.parse(p_value); BigDecimal v_bigDec = new BigDecimal(v_value.doubleValue()); v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP); return v_bigDec.movePointRight(2).intValue(); } catch (ParseException p_ex) { try { // p_value doesn't have a currency format. BigDecimal v_bigDec = new BigDecimal(p_value); v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP); return v_bigDec.movePointRight(2).intValue(); } catch (NumberFormatException p_ex1) { return -1; } } } /** Formats cents into a valid amount using the default currency. * @param p_value Value as cents * @return Amount formatted using a currency. */ public static String formatCentsToAmount(int p_value) { BigDecimal v_bigDec = new BigDecimal(p_value); v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP); v_bigDec = v_bigDec.movePointLeft(2); String v_currency = FORMAT_CURRENCY.format(v_bigDec.doubleValue()); return v_currency.replace(FORMAT_CURRENCY.getCurrency().getSymbol(), "").replace(",", ""); } /** Formats cents into a valid amount using the default currency. * @param p_value Value as cents * @return Amount formatted using a currency. */ public static String formatCentsToCurrency(int p_value) { BigDecimal v_bigDec = new BigDecimal(p_value); v_bigDec = v_bigDec.setScale(2, BigDecimal.ROUND_HALF_UP); v_bigDec = v_bigDec.movePointLeft(2); return FORMAT_CURRENCY.format(v_bigDec.doubleValue()); } } 

这是我的自定义CurrencyEditText

 import android.content.Context; import android.graphics.Rect; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.util.AttributeSet; import android.widget.EditText; import java.math.BigDecimal; import java.text.DecimalFormat; public class CurrencyEditText extends android.support.v7.widget.AppCompatEditText { private static String prefix = "VND "; private static final int MAX_DECIMAL = 3; private CurrencyTextWatcher mCurrencyTextWatcher = new CurrencyTextWatcher(this, prefix); public CurrencyEditText(Context context) { this(context, null); } public CurrencyEditText(Context context, AttributeSet attrs) { this(context, attrs, android.support.v7.appcompat.R.attr.editTextStyle); } public CurrencyEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); this.setHint(prefix); } private static class CurrencyTextWatcher implements TextWatcher { private final EditText mEditText; private String prevString; private String prefix; CurrencyTextWatcher(EditText editText, String prefix) { mEditText = editText; this.prefix = prefix; } @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) { String str = editable.toString(); if (str.length() < prefix.length()) { mEditText.setText(prefix); mEditText.setSelection(prefix.length()); return; } if (str.equals(prefix)) { return; } // cleanString this the string which not contain prefix and , String cleanString = str.replace(prefix, "").replaceAll("[,]", ""); // for prevent afterTextChanged recursive call if (cleanString.equals(prevString) || cleanString.isEmpty()) { return; } prevString = cleanString; String formattedString; if (cleanString.contains(".")) { formattedString = formatDecimal(cleanString); } else { formattedString = formatInteger(cleanString); } mEditText.setText(formattedString); mEditText.setSelection(formattedString.length()); } private String formatInteger(String str) { BigDecimal parsed = new BigDecimal(str); DecimalFormat formatter; formatter = new DecimalFormat(prefix + "#,###"); return formatter.format(parsed); } private String formatDecimal(String str) { if (str.equals(".")) { return prefix + "."; } BigDecimal parsed = new BigDecimal(str); DecimalFormat formatter; // example patter VND #,###.00 formatter = new DecimalFormat(prefix + "#,###." + getDecimalPattern(str)); 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("."); String decimalPattern = ""; for (int i = 0; i < decimalCount && i < MAX_DECIMAL; i++) { decimalPattern += "0"; } return decimalPattern; } } @Override protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(focused, direction, previouslyFocusedRect); if (focused) { this.addTextChangedListener(mCurrencyTextWatcher); if (getText().toString().isEmpty()) { setText(prefix); } } else { this.removeTextChangedListener(mCurrencyTextWatcher); if (getText().toString().equals(prefix)) { setText(""); } } } } 

像XML一样使用它

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

你应该在下面编辑2个常量以适合你的项目

 private static String prefix = "VND "; private static final int MAX_DECIMAL = 3; 

在这里输入图像描述

在github上演示

对我来说,它是这样的

  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]", ""); if (userInput.length() > 2) { Float in=Float.parseFloat(userInput); price = Math.round(in); // just to get an Integer //float percen = in/100; String first, last; first = userInput.substring(0, userInput.length()-2); last = userInput.substring(userInput.length()-2); edEx1.setText("$"+first+"."+last); Log.e(MainActivity.class.toString(), "first: "+first + " last:"+last); edEx1.setSelection(edEx1.getText().length()); } } } 

最好使用InputFilter接口。 通过使用正则表达式来处理任何类型的输入更容易。 我的货币输入格式的解决方案:

 public class CurrencyFormatInputFilter implements InputFilter { Pattern mPattern = Pattern.compile("(0|[1-9]+[0-9]*)(\\.[0-9]{1,2})?"); @Override public CharSequence filter( CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String result = dest.subSequence(0, dstart) + source.toString() + dest.subSequence(dend, dest.length()); Matcher matcher = mPattern.matcher(result); if (!matcher.matches()) return dest.subSequence(dstart, dend); return null; } } 

有效期限:0.00,0.0,10.00,111.1
无效:0,0.000,111,10,010.00,01.0

如何使用:

 editText.setFilters(new InputFilter[] {new CurrencyFormatInputFilter()}); 

即使这里有很多答案,我想分享我在这里找到的代码,因为我相信它是最健壮和最干净的答案。

 class CurrencyTextWatcher implements TextWatcher { boolean mEditing; public CurrencyTextWatcher() { mEditing = false; } public synchronized void afterTextChanged(Editable s) { if(!mEditing) { mEditing = true; String digits = s.toString().replaceAll("\\D", ""); NumberFormat nf = NumberFormat.getCurrencyInstance(); try{ String formatted = nf.format(Double.parseDouble(digits)/100); s.replace(0, s.length(), formatted); } catch (NumberFormatException nfe) { s.clear(); } mEditing = false; } } public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { } } 

希望它有帮助。

我从这里得到这个,并改变它符合葡萄牙货币格式。

 import java.text.NumberFormat; import java.util.Currency; import java.util.Locale; import android.text.Editable; import android.text.TextWatcher; import android.widget.EditText; public class CurrencyTextWatcher implements TextWatcher { private String current = ""; private int index; private boolean deletingDecimalPoint; private final EditText currency; public CurrencyTextWatcher(EditText p_currency) { currency = p_currency; } @Override public void beforeTextChanged(CharSequence p_s, int p_start, int p_count, int p_after) { if (p_after>0) { index = p_s.length() - p_start; } else { index = p_s.length() - p_start - 1; } if (p_count>0 && p_s.charAt(p_start)==',') { deletingDecimalPoint = true; } else { deletingDecimalPoint = false; } } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable p_s) { if(!p_s.toString().equals(current)){ currency.removeTextChangedListener(this); if (deletingDecimalPoint) { p_s.delete(p_s.length()-index-1, p_s.length()-index); } // Currency char may be retrieved from NumberFormat.getCurrencyInstance() String v_text = p_s.toString().replace("€","").replace(",", ""); v_text = v_text.replaceAll("\\s", ""); double v_value = 0; if (v_text!=null && v_text.length()>0) { v_value = Double.parseDouble(v_text); } // Currency instance may be retrieved from a static member. NumberFormat numberFormat = NumberFormat.getCurrencyInstance(new Locale("pt", "PT")); String v_formattedValue = numberFormat.format((v_value/100)); current = v_formattedValue; currency.setText(v_formattedValue); if (index>v_formattedValue.length()) { currency.setSelection(v_formattedValue.length()); } else { currency.setSelection(v_formattedValue.length()-index); } // include here anything you may want to do after the formatting is completed. currency.addTextChangedListener(this); } } } 

layout.xml

 <EditText android:id="@+id/edit_text_your_id" ... android:text="0,00 €" android:inputType="numberDecimal" android:digits="0123456789" /> 

让它工作

  yourEditText = (EditText) findViewById(R.id.edit_text_your_id); yourEditText.setRawInputType(Configuration.KEYBOARD_12KEY); yourEditText.addTextChangedListener(new CurrencyTextWatcher(yourEditText)); 

如果你的JSON货币字段是数字类型(而不是字符串),它可能会来3.1,3.15或只是3.因为JSON自动轮数字段。

在这种情况下,您可能需要将其四舍五入才能正确显示(并且可以稍后在输入字段中使用掩码):

  NumberFormat nf = NumberFormat.getCurrencyInstance(); float value = 200 // it can be 200, 200.3 or 200.37, BigDecimal will take care BigDecimal valueAsBD = BigDecimal.valueOf(value); valueAsBD.setScale(2, BigDecimal.ROUND_HALF_UP); String formated = nf.format(valueAsBD); 

为什么这是必要的?

所有的答案指出,当打字时,删除货币符号判断你正在收到美分,因此形成dolar +美分/ 100 = dolar,美分。 但是,如果你的json货币字段是一个数字类型(而不是一个字符串),它将围绕你的美分,它可能是3,3.1或3.15。

我用它来允许用户输入货币,并将其从字符串转换为整型,以存储在数据库中,并从int再次更改为字符串

https://github.com/nleigh/Restaurant/blob/master/Restaurant/src/uk/co/nathanleigh/restaurant/CurrencyFormat.java

在查看大多数的StackOverflow帖子以不同的方式来实现这个使用TextWatcherInputFilter ,或者像CurrencyEditText这样的库我已经解决了这个简单的解决方案使用OnFocusChangeListener

逻辑是将EditText解析为一个数字,当它被聚焦时,并在失去焦点时将其格式化。

 amount.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean hasFocus) { Number numberAmount = 0f; try { numberAmount = Float.valueOf(amount.getText().toString()); } catch (NumberFormatException e1) { e1.printStackTrace(); try { numberAmount = NumberFormat.getCurrencyInstance().parse(amount.getText().toString()); } catch (ParseException e2) { e2.printStackTrace(); } } if (hasFocus) { amount.setText(numberAmount.toString()); } else { amount.setText(NumberFormat.getCurrencyInstance().format(numberAmount)); } } }); 

我已经实施了Kotlin + Rx版本。

这是巴西货币(例如1,500.00 – 5,21 – 192,90),但您可以轻松地适应其他格式。

希望别人觉得有帮助。

 RxTextView .textChangeEvents(fuel_price) // Observe text event changes .filter { it.text().isNotEmpty() } // do not accept empty text when event first fires .flatMap { val onlyNumbers = Regex("\\d+").findAll(it.text()).fold(""){ acc:String,it:MatchResult -> acc.plus(it.value)} Observable.just(onlyNumbers) } .distinctUntilChanged() .map { it.trimStart('0') } .map { when (it.length) { 1-> "00"+it 2-> "0"+it else -> it } } .subscribe { val digitList = it.reversed().mapIndexed { i, c -> if ( i == 2 ) "${c}," else if ( i < 2 ) c else if ( (i-2)%3==0 ) "${c}." else c } val currency = digitList.reversed().fold(""){ acc,it -> acc.toString().plus(it) } fuel_price.text = SpannableStringBuilder(currency) fuel_price.setSelection(currency.length) } 

另一种方法,但基于Guilherme的答案 。 当您的国家区域设置不可用时,或者如果您要使用自定义货币符号,此方法是有用的。 此实现仅用于正数非小数。

这个代码是在Kotlin中,第一个委托setMaskingMoneyEditText

 fun EditText.setMaskingMoney(currencyText: String) { this.addTextChangedListener(object: MyTextWatcher{ val editTextWeakReference: WeakReference<EditText> = WeakReference<EditText>(this@setMaskingMoney) override fun afterTextChanged(editable: Editable?) { val editText = editTextWeakReference.get() ?: return val s = editable.toString() editText.removeTextChangedListener(this) val cleanString = s.replace("[Rp,. ]".toRegex(), "") val newval = currencyText + cleanString.monetize() editText.setText(newval) editText.setSelection(newval.length) editText.addTextChangedListener(this) } }) } 

那么MyTextWatcher接口应该从TextWatcher扩展。 由于我们只需要afterTextChanged方法,所以其他的方法需要在这个接口中afterTextChanged

 interface MyTextWatcher: TextWatcher { override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} } 

而货币化的方法是:

 fun String.monetize(): String = if (this.isEmpty()) "0" else DecimalFormat("#,###").format(this.replace("[^\\d]".toRegex(),"").toLong()) 

完整的实现:

 fun EditText.setMaskingMoney(currencyText: String) { this.addTextChangedListener(object: MyTextWatcher{ val editTextWeakReference: WeakReference<EditText> = WeakReference<EditText>(this@setMaskingMoney) override fun afterTextChanged(editable: Editable?) { val editText = editTextWeakReference.get() ?: return val s = editable.toString() editText.removeTextChangedListener(this) val cleanString = s.replace("[Rp,. ]".toRegex(), "") val newval = currencyText + cleanString.monetize() editText.setText(newval) editText.setSelection(newval.length) editText.addTextChangedListener(this) } }) } interface MyTextWatcher: TextWatcher { override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {} } fun String.monetize(): String = if (this.isEmpty()) "0" else DecimalFormat("#,###").format(this.replace("[^\\d]".toRegex(),"").toLong()) 

并在onCreate方法的某处:

 yourTextView.setMaskingMoney("Rp. ") 

CurrencyTextWatcher.java

 public class CurrencyTextWatcher implements TextWatcher { private final static String DS = "."; //Decimal Separator private final static String TS = ","; //Thousands Separator private final static String NUMBERS = "0123456789"; //Numbers private final static int MAX_LENGTH = 13; //Maximum Length private String format; private DecimalFormat decimalFormat; private EditText editText; public CurrencyTextWatcher(EditText editText) { String pattern = "###" + TS + "###" + DS + "##"; decimalFormat = new DecimalFormat(pattern); this.editText = editText; this.editText.setInputType(InputType.TYPE_CLASS_NUMBER); this.editText.setKeyListener(DigitsKeyListener.getInstance(NUMBERS + DS)); this.editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(MAX_LENGTH)}); } @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 value = editable.toString(); if (!value.isEmpty()) { value = value.replace(TS, ""); try { format = decimalFormat.format(Double.parseDouble(value)); format = format.replace("0", ""); } catch (Exception e) { System.out.println(e.getMessage()); } editText.setText(format); } editText.addTextChangedListener(this); } } 

EditTextCurrency.java

 public class EditTextCurrency extends AppCompatEditText { public EditTextCurrency(Context context) { super(context); } public EditTextCurrency(Context context, AttributeSet attrs) { super(context, attrs); addTextChangedListener(new CurrencyTextWatcher(this)); } } 

在这里输入图像描述