更好的方式来格式货币inputeditText?
我有一个editText,起始值是$ 0.00。 当您按1时,它将更改为$ 0.01。 按4,到$ 0.14。 按8,$ 1.48。 按退格键,$ 0.14等
这是有效的,问题是,如果有人手动定位光标,格式化会出现问题。 如果他们要删除小数,它不会回来。 如果他们把光标放在小数点前面并input2,它将显示$ 02.00而不是$ 2.00。 如果他们试图删除$,它将删除一个数字,例如。
这里是我正在使用的代码,我会很感激任何build议。
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()); } } } });
我testing了你的方法,但是当我使用很多数字的时候失败了…我创build了这个:
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); } }
根据上面的一些答案,我创build了一个您将使用的MoneyTextWatcher,如下所示:
priceEditText.addTextChangedListener(new MoneyTextWatcher(priceEditText));
这里是class级:
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); } }
实际上,之前提供的解决scheme不起作用。 如果您想input100.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){ //logging一些东西 } } } @覆盖 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)(。,)]”,“”); 返回格式化; } }
我build立在Guilhermes的答案上,但我保留了光标的位置,并以不同的方式处理期间 – 这样,如果用户在该期间后打字,它不会影响数字之前,我发现这会给一个非常stream畅的input。
[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代码…但是,处理一些与向后删除和一些parsingexception相关的问题: http : //miguelt.blogspot.ca/2013/01/textwatcher-for-currency-masksformatting .html [更新]以前的解决scheme有一些问题…这是一个更好的解决scheme: 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类 – 实现可以在“金额,税收”中find。
/** 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); } } }
这个类将在编辑时删除货币格式 – 依靠标准机制。 当用户退出时,货币格式被重新应用。
最好定义一些静态variables来最小化实例的数量:
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接口。 通过使用正则expression式来处理任何types的input更容易。 我的货币input格式的解决scheme:
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()});
即使这里有很多答案,我想分享我在这里find的代码,因为我相信它是最健壮和最干净的答案。
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货币字段是数字types(而不是string),它可能会来3.1,3.15或只是3.因为JSON自动轮数字段。
在这种情况下,您可能需要将其四舍五入才能正确显示(并且可以稍后在input字段中使用掩码):
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货币字段是一个数字types(而不是一个string),它将围绕你的美分,它可能是3,3.1或3.15。
我用它来允许用户input货币,并将其从string转换为整型,以存储在数据库中,并从int再次更改为string
在查看大多数的StackOverflowpost以不同的方式来实现这个使用TextWatcher
, InputFilter
,或者像CurrencyEditText这样的库我已经解决了这个简单的解决scheme使用OnFocusChangeListener
。
逻辑是将EditText
parsing为一个数字,当它被聚焦时,并在失去焦点时将其格式化。
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中,第一个委托setMaskingMoney
为EditText
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)); } }