Android – Cómo permitir sólo un cierto número de lugares decimales
¿Conoce algún método para asegurarse de que los usuarios sólo pueden introducir cifras con un número máximo de decimales. No estoy seguro de cómo abordar este problema. En la base de datos MS SQL voy a enviar datos de mi aplicación Tengo columnas con este tipo decimal(8,3)
Ahora, teniendo en cuenta el tipo de datos de la columna que finalmente va a almacenar el valor que quiero validar en Android , He considerado estos dos casos:
- Si el usuario introduce un número sin decimales, el número máximo de dígitos debe ser 8
- Si el usuario introduce un número con decimales, el número máximo de dígitos debe ser 8 (incluidos los dígitos a la derecha del punto decimal)
Ahora estoy seguro sobre el primer caso, pero no tanto sobre el segundo. ¿Es correcto mantener fijo el número de dígitos máximos (por ejemplo, siempre 8)? ¿O debo considerar permitir un máximo de 8 dígitos a la izquierda y 3 a la derecha de la coma decimal?
- Retrofit: 500 error de servidor interno
- ¿Por qué overridePendingTransition no tiene efecto cuando salto de Fragment a una nueva Activity?
- La aplicación de Android no se inicia en simulador o hardware
- Cambiar el ancho y la altura de la vista personalizada en Android
- Análisis de un sitio web con Jsoup que se carga dinámicamente a medida que el usuario se desplaza
De cualquier manera esto es lo que he estado intentando en Android:
mQuantityEditText.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) { String str = mQuantityEditText.getText().toString(); DecimalFormat format = (DecimalFormat) DecimalFormat .getInstance(); DecimalFormatSymbols symbols = format.getDecimalFormatSymbols(); char sep = symbols.getDecimalSeparator(); int indexOFdec = str.indexOf(sep); if (indexOFdec >= 0) { if (str.substring(indexOFdec, str.length() - 1).length() > 3) { s.replace(0, s.length(), str.substring(0, str.length() - 1)); } } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } });
Aunque, el código anterior maneja el número máximo de decimales. No limita el número total de dígitos permitidos en el EditText.
¿Crees que podrías ayudarme a mejorar mi código para que maneje tanto el número máximo de decimales como el número total de dígitos permitidos en un EditText (considerando tanto los números a la izquierda como a la derecha del punto decimal)
EDITAR
Bueno, ahora estoy intentando lo que sugirió João Sousa y aquí está lo que he probado:
1) Definí una clase que implementa InputFilter
public class NumberInputFilter implements InputFilter { private Pattern mPattern; public NumberInputFilter(int precision, int scale) { String pattern="^\\-?(\\d{0," + (precision-scale) + "}|\\d{0," + (precision-scale) + "}\\.\\d{0," + scale + "})$"; this.mPattern=Pattern.compile(pattern); } @Override public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) { if (end > start) { // adding: filter // build the resulting text String destinationString = destination.toString(); String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd); // return null to accept the input or empty to reject it return resultingTxt.matches(this.mPattern.toString()) ? null : ""; } // removing: always accept return null; } }
2) Trató de usar la clase así:
mQuantityEditText.setFilters(new InputFilter[] { new NumberInputFilter(8,3)} );
- Agregar oyentes diferentes para texto en TextView
- Gradle build failed: Los archivos Dex no pueden superar los 64k
- Android / Java: largo obtiene negativo sin superar max_value
- ¿Cómo enviar datos multipart / form a un servidor web desde android?
- Problema del adaptador simple, texto + imagen en hilandero. Java, Android
- java.lang.IllegalStateException: Necesita usar un tema Theme.AppCompat (o descendente) con esta actividad
- Envío de flujo de imágenes por problema de socket: Android
- AsyncTask con rotación de pantalla - onRetainNonConfigurationInstance obsoleta
Yo iría por un filtro en el propio texto de edición con el poder de regex. Primero la expresión regex:
^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$
Tal vez hay varias maneras de mejorar esta expresión, pero esto no truco.
Y ahora acaba de establecer un filtro de entrada en el edittext, así:
final String regex = "^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$"; ((EditText)rootView.findViewById(R.id.editText1)).setFilters(new InputFilter[] { new InputFilter() { @Override public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) { if (end > start) { // adding: filter // build the resulting text String destinationString = destination.toString(); String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd); // return null to accept the input or empty to reject it return resultingTxt.matches(regex) ? null : ""; } // removing: always accept return null; } } });
Por cierto, acabo de probar este código y lo que hace es:
- El usuario puede ingresar un máximo de 8 dígitos;
- Tan pronto como el usuario ingresa un '.', Los dígitos decimales máximos permitidos son 8.
¿Entendí correctamente el problema que describió?
– EDITAR
Ok, yo estaba casi allí. Por lo que entiendo, decimal (8,3) significa un máximo de 8 dígitos, incluyendo dígitos a la izquierda o derecha del punto decimal, que van desde -99999.999
a 99999.999
. Por lo menos eso es lo que entiendo de esta frase Standard SQL requires that DECIMAL(5,2) be able to store any value with five digits and two decimals, so values that can be stored in the salary column range from -999.99 to 999.99
. A pesar de que es de la documentación de MySQL los documentos MSSQL parecen hacer lo mismo.
Tengo respuesta para usted, yo también sufrido mucho en este tipo de situation.:D: P
He implementado esto para un máximo de 4 dígitos a la izquierda y 2 a la derecha del punto decimal ex: 4444.99
Tan pequeños cambios necesitan para implementar lo que hice: Necesidad de hacer los siguientes cambios
1) copia CustomTextWatcher.java para rastrear la entrada de editText.
import java.text.NumberFormat; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.widget.EditText; public class CustomTextWatcher implements TextWatcher { private NumberFormat nf = NumberFormat.getNumberInstance(); private EditText et; private String tmp = ""; private int moveCaretTo; private static final int INTEGER_CONSTRAINT = 4; private static final int FRACTION_CONSTRAINT = 2; private static final int MAX_LENGTH = INTEGER_CONSTRAINT + FRACTION_CONSTRAINT + 1; public CustomTextWatcher(EditText et) { this.et = et; nf.setMaximumIntegerDigits(INTEGER_CONSTRAINT); nf.setMaximumFractionDigits(FRACTION_CONSTRAINT); nf.setGroupingUsed(false); } public int countOccurrences(String str, char c) { int count = 0; for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == c) { count++; } } return count; } @Override public void afterTextChanged(Editable s) { et.removeTextChangedListener(this); // remove to prevent stackoverflow String ss = s.toString(); int len = ss.length(); int dots = countOccurrences(ss, '.'); boolean shouldParse = dots <= 1 && (dots == 0 ? len != (INTEGER_CONSTRAINT + 1) : len < (MAX_LENGTH + 1)); if (shouldParse) { if (len > 1 && ss.lastIndexOf(".") != len - 1) { try { if (ss.contains(".")) { String[] integerFractionStrings = ss.split("\\."); Log.v("Check SS ", ss); Log.v("second string", "Found" + integerFractionStrings.length); if (integerFractionStrings.length > 1) { Log.v("integerFractionStrings", integerFractionStrings[1]); if (integerFractionStrings[1].length() == 1 && integerFractionStrings[1].charAt(0) == '0') { et.setText(ss); Log.v("second string", "size 1"); } else { Log.v("second string", "> 1"); Double d = Double.parseDouble(ss); if (d != null) { et.setText(nf.format(d)); } } } } else { Log.v("First string", "No dot"); Double d = Double.parseDouble(ss); if (d != null) { et.setText(nf.format(d)); } } } catch (NumberFormatException e) { } } } else { Log.v("second string", "size 1"); et.setText(tmp); } et.addTextChangedListener(this); // reset listener // tried to fix caret positioning after key type: if (et.getText().toString().length() > 0) { if (dots == 0 && len >= INTEGER_CONSTRAINT && moveCaretTo > INTEGER_CONSTRAINT) { moveCaretTo = INTEGER_CONSTRAINT; } else if (dots > 0 && len >= (MAX_LENGTH) && moveCaretTo > (MAX_LENGTH)) { moveCaretTo = MAX_LENGTH; } try { et.setSelection(et.getText().toString().length()); // et.setSelection(moveCaretTo); <- almost had it :)) } catch (Exception e) { } } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { moveCaretTo = et.getSelectionEnd(); tmp = s.toString(); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { int length = et.getText().toString().length(); if (length > 0) { moveCaretTo = start + count - before; } } }
2) Establezca esta clase para comprobar su editText siguiendo.
EditText review_food_Price; review_food_Price = (EditText) findViewById(R.id.food_Price); review_food_Price.setRawInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); review_food_Price.addTextChangedListener(new CustomTextWatcher( review_food_Price));
Esperanza usted puede convertir mi código según su necesidad.
El problema que describen es precisamente lo que se pretende utilizar para un Texto de edición enmascarado . 🙂