Respuestas:
Encontré esto en otro foro. Funciona como un campeón.
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (!Character.isLetterOrDigit(source.charAt(i))) {
return "";
}
}
return null;
}
};
edit.setFilters(new InputFilter[] { filter });
InputFilter
Los s son un poco complicados en las versiones de Android que muestran sugerencias de diccionario. A veces se obtiene un SpannableStringBuilder
, a veces un plano String
en el source
parámetro.
Lo siguiente InputFilter
debería funcionar. ¡Siéntase libre de mejorar este código!
new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
if (source instanceof SpannableStringBuilder) {
SpannableStringBuilder sourceAsSpannableBuilder = (SpannableStringBuilder)source;
for (int i = end - 1; i >= start; i--) {
char currentChar = source.charAt(i);
if (!Character.isLetterOrDigit(currentChar) && !Character.isSpaceChar(currentChar)) {
sourceAsSpannableBuilder.delete(i, i+1);
}
}
return source;
} else {
StringBuilder filteredStringBuilder = new StringBuilder();
for (int i = start; i < end; i++) {
char currentChar = source.charAt(i);
if (Character.isLetterOrDigit(currentChar) || Character.isSpaceChar(currentChar)) {
filteredStringBuilder.append(currentChar);
}
}
return filteredStringBuilder.toString();
}
}
}
String replacement = source.subSequence(start, end).toString(); return replacement.replaceAll("[^A-Za-z0-9_\\-@]", "");
source instanceof SpannableStringBuilder
ingresar AB me da AAB como cuando intento la respuesta anterior. Afortunadamente, pude solucionarlo usando la solución @florian a continuación.
más fácil:
<EditText
android:inputType="text"
android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />
","
en el medio. Puede usar algo como esto"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
imeOptions="actionNext"
, etc.
Ninguna de las respuestas publicadas funcionó para mí. Vine con mi propia solución:
InputFilter filter = new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
boolean keepOriginal = true;
StringBuilder sb = new StringBuilder(end - start);
for (int i = start; i < end; i++) {
char c = source.charAt(i);
if (isCharAllowed(c)) // put your condition here
sb.append(c);
else
keepOriginal = false;
}
if (keepOriginal)
return null;
else {
if (source instanceof Spanned) {
SpannableString sp = new SpannableString(sb);
TextUtils.copySpansFrom((Spanned) source, start, sb.length(), null, sp, 0);
return sp;
} else {
return sb;
}
}
}
private boolean isCharAllowed(char c) {
return Character.isLetterOrDigit(c) || Character.isSpaceChar(c);
}
}
editText.setFilters(new InputFilter[] { filter });
EditText
ya puede tener sus propios filtros, por ejemplo, filtro de longitud. Entonces, en lugar de anular los filtros, lo más probable es que desee agregar sus filtros a los ya existentes.
Utilice este su trabajo 100% su necesidad y muy simple.
<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />
En strings.xml
<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>
Para evitar caracteres especiales en el tipo de entrada
public static InputFilter filter = new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String blockCharacterSet = "~#^|$%*!@/()-'\":;,?{}=!$^';,?×÷<>{}€£¥₩%~`¤♡♥_|《》¡¿°•○●□■◇◆♧♣▲▼▶◀↑↓←→☆★▪:-);-):-D:-(:'(:O 1234567890";
if (source != null && blockCharacterSet.contains(("" + source))) {
return "";
}
return null;
}
};
Puede configurar el filtro para su texto de edición como a continuación
edtText.setFilters(new InputFilter[] { filter });
Además de la respuesta aceptada, también es posible usar, por ejemplo: android:inputType="textCapCharacters"
como un atributo de <EditText>
, para aceptar solo letras mayúsculas (y números).
Por alguna razón, el constructor de la clase android.text.LoginFilter tiene un alcance de paquete, por lo que no puede extenderlo directamente (aunque sería idéntico a este código). ¡Pero puede extender LoginFilter.UsernameFilterGeneric! Entonces solo tienes esto:
class ABCFilter extends LoginFilter.UsernameFilterGeneric {
public UsernameFilter() {
super(false); // false prevents not-allowed characters from being appended
}
@Override
public boolean isAllowed(char c) {
if ('A' <= c && c <= 'C')
return true;
if ('a' <= c && c <= 'c')
return true;
return false;
}
}
Esto no está realmente documentado, pero es parte de la biblioteca principal y la fuente es sencilla . Lo he estado usando durante un tiempo, hasta ahora no hay problemas, aunque admito que no he intentado hacer nada complejo que involucre spannables.
Es correcto, la mejor manera de solucionarlo en el propio diseño XML utilizando:
<EditText
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
como acertadamente señaló Florian Fröhlich, funciona bien incluso para vistas de texto.
<TextView
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
Solo una advertencia, los caracteres mencionados en el android:digits
solo se mostrarán, así que tenga cuidado de no perder ningún conjunto de caracteres :)
inputType
no afecta el filtrado.
Esta solución simple funcionó para mí cuando necesitaba evitar que el usuario ingresara cadenas vacías en un EditText. Por supuesto, puede agregar más personajes:
InputFilter textFilter = new InputFilter() {
@Override
public CharSequence filter(CharSequence c, int arg1, int arg2,
Spanned arg3, int arg4, int arg5) {
StringBuilder sbText = new StringBuilder(c);
String text = sbText.toString();
if (text.contains(" ")) {
return "";
}
return c;
}
};
private void setTextFilter(EditText editText) {
editText.setFilters(new InputFilter[]{textFilter});
}
Si subclasifica InputFilter, puede crear su propio InputFilter que filtraría los caracteres no alfanuméricos.
La interfaz InputFilter tiene un método, filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
y le proporciona toda la información que necesita para saber qué caracteres se ingresaron en el EditText al que está asignado.
Una vez que haya creado su propio InputFilter, puede asignarlo al EditText llamando a setFilters (...).
http://developer.android.com/reference/android/text/InputFilter.html#filter(java.lang.CharSequence , int, int, android.text.Spanned, int, int)
Ignorando las cosas de la extensión con las que otras personas se han ocupado, para manejar adecuadamente las sugerencias del diccionario, encontré que el siguiente código funciona.
La fuente crece a medida que crece la sugerencia, por lo que tenemos que ver cuántos caracteres realmente espera que reemplacemos antes de devolver cualquier cosa.
Si no tenemos caracteres no válidos, devuelva nulo para que ocurra el reemplazo predeterminado.
De lo contrario, debemos extraer los caracteres válidos de la subcadena que REALMENTE se colocará en EditText.
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
boolean includesInvalidCharacter = false;
StringBuilder stringBuilder = new StringBuilder();
int destLength = dend - dstart + 1;
int adjustStart = source.length() - destLength;
for(int i=start ; i<end ; i++) {
char sourceChar = source.charAt(i);
if(Character.isLetterOrDigit(sourceChar)) {
if(i >= adjustStart)
stringBuilder.append(sourceChar);
} else
includesInvalidCharacter = true;
}
return includesInvalidCharacter ? stringBuilder : null;
}
};
para evitar palabras en edittext. crea una clase que puedas usar en cualquier momento.
public class Wordfilter implements InputFilter
{
@Override
public CharSequence filter(CharSequence source, int start, int end,Spanned dest, int dstart, int dend) {
// TODO Auto-generated method stub
boolean append = false;
String text = source.toString().substring(start, end);
StringBuilder str = new StringBuilder(dest.toString());
if(dstart == str.length())
{
append = true;
str.append(text);
}
else
str.replace(dstart, dend, text);
if(str.toString().contains("aaaaaaaaaaaa/*the word here*/aaaaaaaa"))
{
if(append==true)
return "";
else
return dest.subSequence(dstart, dend);
}
return null;
}
}
Primero agregue a strings.xml
:
<string name="vin_code_mask">0123456789abcdefghjklmnprstuvwxyz</string>
XML :
android:digits="@string/vin_code_mask"
Código en Kotlin:
edit_text.filters += InputFilter { source, start, end, _, _, _ ->
val mask = getString(R.string.vin_code_mask)
for (i in start until end) {
if (!mask.contains(source[i])) {
return@InputFilter ""
}
}
null
}
Es extraño, pero funciona de forma extraña en el teclado suave del emulador.
¡Advertencia! El siguiente código filtrará todas las letras y otros símbolos, excepto los dígitos para los teclados de software. Solo el teclado digital aparecerá en los teléfonos inteligentes.
edit_text.keyListener = DigitsKeyListener.getInstance(context.getString(R.string.vin_code_mask))
Asimismo, establecer por lo general maxLength
, filters
, inputType
.
Este es un hilo antiguo, pero las soluciones propuestas tienen problemas (dependiendo del dispositivo / versión de Android / Teclado).
ENFOQUE DIFERENTE
Así que finalmente fui con un enfoque diferente, en lugar de usar la InputFilter
implementación problemática, estoy usando TextWatcher
y el TextChangedListener
de EditText
.
CÓDIGO COMPLETO (EJEMPLO)
editText.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
super.afterTextChanged(editable);
String originalText = editable.toString();
int originalTextLength = originalText.length();
int currentSelection = editText.getSelectionStart();
// Create the filtered text
StringBuilder sb = new StringBuilder();
boolean hasChanged = false;
for (int i = 0; i < originalTextLength; i++) {
char currentChar = originalText.charAt(i);
if (isAllowed(currentChar)) {
sb.append(currentChar);
} else {
hasChanged = true;
if (currentSelection >= i) {
currentSelection--;
}
}
}
// If we filtered something, update the text and the cursor location
if (hasChanged) {
String newText = sb.toString();
editText.setText(newText);
editText.setSelection(currentSelection);
}
}
private boolean isAllowed(char c) {
// TODO: Add the filter logic here
return Character.isLetter(c) || Character.isSpaceChar(c);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do Nothing
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Do Nothing
}
});
La razón por la InputFilter
que no es una buena solución en Android es que depende de la implementación del teclado. La entrada del teclado se está filtrando antes de pasar la entrada al EditText
. Pero, dado que algunos teclados tienen implementaciones diferentes para la InputFilter.filter()
invocación, esto es problemático.
Por otro lado, TextWatcher
no le importa la implementación del teclado, nos permite crear una solución simple y asegurarnos de que funcione en todos los dispositivos.
onTextChanged
simplemente necesita un public void
frente.
He hecho algo como esto para que sea simple:
edit_text.filters = arrayOf(object : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
return source?.subSequence(start, end)
?.replace(Regex("[^A-Za-z0-9 ]"), "")
}
})
De esta manera, estamos reemplazando todos los caracteres no deseados en la nueva parte de la cadena de origen con una cadena vacía.
La edit_text
variable es el EditText
objeto al que nos referimos.
El código está escrito en kotlin
.
Es posible de usar setOnKeyListener
. ¡En este método, podemos personalizar la entrada edittext
!
Así es como creé el filtro para el campo Nombre en Editar texto. (La primera letra es MAYÚSCULAS, y permite solo un espacio después de cada palabra.
public void setNameFilter() {
InputFilter filter = new InputFilter() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (dend == 0) {
if (Character.isSpaceChar(source.charAt(i)) ||
!Character.isAlphabetic(source.charAt(i))) {
return Constants.Delimiter.BLANK;
} else {
return String.valueOf(source.charAt(i)).toUpperCase();
}
} else if (Character.isSpaceChar(source.charAt(i)) &&
String.valueOf(dest).endsWith(Constants.Delimiter.ONE_SPACE)) {
return Constants.Delimiter.BLANK;
} else if ((!Character.isSpaceChar(source.charAt(i)) &&
!Character.isAlphabetic(source.charAt(i)))) {
return Constants.Delimiter.BLANK;
}
}
return null;
}
};
editText.setFilters(new InputFilter[]{filter, new InputFilter.LengthFilter(Constants.Length.NAME_LENGTH)});
}
Tengo la misma respuesta en Kotlin:
/**
* Returns the filter of the editText'es CharSequence value when [filterType] is:
* 1 -> letters; 2 -> letters and digits; 3 -> digits;
* 4 -> digits and dots
*/
class InputFilterAlphanumeric(private val filterType: Int): InputFilter {
override fun filter(source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence {
(source as? SpannableStringBuilder)?.let {sourceAsSpannableBuilder ->
for (i in (end - 1) downTo start) {
val currentChar = source[i]
when(filterType) {
1 -> {
if (!currentChar.isLetter() && !currentChar.isWhitespace()) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
2 -> {
if (!currentChar.isLetterOrDigit() && !currentChar.isWhitespace()) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
3 -> {
if (!currentChar.isDigit()) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
4 -> {
if (!currentChar.isDigit() || !currentChar.toString().contains(".")) {
sourceAsSpannableBuilder.delete(i, i + 1)
}
}
}
}
return source
} ?: run {
val filteredStringBuilder = StringBuilder()
for (i in start until end) {
val currentChar = source?.get(i)
when(filterType) {
1 -> {
if (currentChar?.isLetter()!! || currentChar.isWhitespace()) {
filteredStringBuilder.append(currentChar)
}
}
2 -> {
if (currentChar?.isLetterOrDigit()!! || currentChar.isWhitespace()) {
filteredStringBuilder.append(currentChar)
}
}
3 -> {
if (currentChar?.isDigit()!!) {
filteredStringBuilder.append(currentChar)
}
}
4 -> {
if (currentChar?.isDigit()!! || currentChar.toString().contains(".")) {
filteredStringBuilder.append(currentChar)
}
}
}
}
return filteredStringBuilder
}
}
}
y obtener la clase con una función de extensión:
fun EditText.filterByDataType(filterType: Int) {
this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}