Ok, voici une meilleure façon de gérer les formats de devise, la suppression de l'entrée en arrière. Le code est basé sur le code de @androidcurious ci-dessus... Mais, traite certains problèmes liés à la suppression en arrière et certaines exceptions d'analyse : http://miguelt.blogspot.ca/2013/01/textwatcher-for-currency-masksformatting.html [MISE À JOUR] La solution précédente avait certains problèmes... Voici une meilleure solution : http://miguelt.blogspot.ca/2013/02/update-textwatcher-for-currency.html Et... voici les détails :
Cette approche est meilleure car elle utilise les mécanismes Android conventionnels. L'idée est de formater les valeurs après que l'utilisateur quitte la vue.
Définir un InputFilter pour restreindre les valeurs numériques - cela est nécessaire dans la plupart des cas car l'écran n'est pas assez grand pour accueillir de longues vues EditText. Cela peut être une classe interne statique ou juste une autre classe simple :
/** Filtre de plage numérique. */
class NumericRangeFilter implements InputFilter {
/** Valeur maximale. */
private final double maximum;
/** Valeur minimale. */
private final double minimum;
/** Crée un nouveau filtre entre 0.00 et 999 999.99. */
NumericRangeFilter() {
this(0.00, 999999.99);
}
/** Crée un nouveau filtre.
* @param p_min Valeur minimale.
* @param p_max Valeur maximale.
*/
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) {
// Retourner null permettra à EditText d'accepter plus de valeurs.
return null;
}
} catch (NumberFormatException p_ex) {
// ne rien faire
}
// La valeur est hors de la plage - retourner une chaîne vide.
return "";
}
}
Définir une classe (statique interne ou juste une classe) qui implémentera View.OnFocusChangeListener. Notez que j'utilise une classe Utils - l'implémentation peut être trouvée à "Amounts, Taxes".
/** Utilisé pour formater les vues de montant. */
class AmountOnFocusChangeListener implements View.OnFocusChangeListener {
@Override
public void onFocusChange(View p_view, boolean p_hasFocus) {
// Ce listener sera attaché à toute vue contenant des montants.
EditText v_amountView = (EditText)p_view;
if (p_hasFocus) {
// v_value utilise un masque de devise - le transformer en cents.
String v_value = v_amountView.getText().toString();
int v_cents = Utils.parseAmountToCents(v_value);
// Maintenant, formater les cents en un montant (sans masque de devise)
v_value = Utils.formatCentsToAmount(v_cents);
v_amountView.setText(v_value);
// Sélectionner tout afin que l'utilisateur puisse écraser tout le montant en une seule fois.
v_amountView.selectAll();
} else {
// v_value n'utilise pas de masque de devise - le transformer en cents.
String v_value = v_amountView.getText().toString();
int v_cents = Utils.parseAmountToCents(v_value);
// Maintenant, formater les cents en un montant (avec masque de devise)
v_value = Utils.formatCentsToCurrency(v_cents);
v_amountView.setText(v_value);
}
}
}
Cette classe supprimera le format de devise lors de l'édition - en s'appuyant sur des mécanismes standard. Lorsque l'utilisateur quitte, le format de devise est réappliqué.
Il est préférable de définir quelques variables statiques pour minimiser le nombre d'instances :
static final InputFilter[] FILTERS = new InputFilter[] {new NumericRangeFilter()};
static final View.OnFocusChangeListener ON_FOCUS = new AmountOnFocusChangeListener();
Enfin, dans le onCreateView(...):
EditText mAmountView = ....
mAmountView.setFilters(FILTERS);
mAmountView.setOnFocusChangeListener(ON_FOCUS);
Vous pouvez réutiliser FILTERS et ON_FOCUS sur autant de vues EditText que nécessaire.
Voici la classe Utils :
public class Utils {
private static final NumberFormat FORMAT_CURRENCY = NumberFormat.getCurrencyInstance();
/** Analyse un montant en cents.
* @param p_value Montant formaté en utilisant la devise par défaut.
* @return Valeur en 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 n'a pas de format de devise.
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;
}
}
}
/** Formate les cents en un montant valide en utilisant la devise par défaut.
* @param p_value Valeur en cents
* @return Montant formaté en utilisant une devise.
*/
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(",", "");
}
/** Formate les cents en un montant valide en utilisant la devise par défaut.
* @param p_value Valeur en cents
* @return Montant formaté en utilisant une devise.
*/
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());
}
}