Respostas:
Encontrei isso em outro fórum. Funciona como um campeão.
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
s são um pouco complicados nas versões do Android que exibem sugestões de dicionário. Você às vezes recebe um SpannableStringBuilder
, às vezes uma planície String
no source
parâmetro
O seguinte InputFilter
deve funcionar. Sinta-se livre para melhorar 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
digitar AB me dá AAB, como ao tentar a resposta anterior. Felizmente, consegui contornar o problema usando a solução @florian abaixo.
muito facil:
<EditText
android:inputType="text"
android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />
","
. Você pode usar algo como isto"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
imeOptions="actionNext"
, etc.
Nenhuma das respostas postadas funcionou para mim. Eu vim com minha própria solução:
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
que já pode ter seus próprios filtros, por exemplo, filtro de comprimento. Portanto, em vez de substituir os filtros, você provavelmente deseja adicionar seus filtros aos já existentes.
Use isso seu trabalho 100% da sua necessidade e muito simples.
<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />
Em strings.xml
<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>
Para evitar caracteres especiais no 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;
}
};
Você pode definir o filtro para o seu texto de edição, como abaixo
edtText.setFilters(new InputFilter[] { filter });
Além da resposta aceita, também é possível usar, por exemplo: android:inputType="textCapCharacters"
como um atributo de <EditText>
, para aceitar apenas caracteres maiúsculos (e números).
Por alguma razão, o construtor da classe android.text.LoginFilter tem o escopo do pacote, portanto você não pode estendê-lo diretamente (mesmo que seja idêntico a esse código). Mas você pode estender o LoginFilter.UsernameFilterGeneric! Então você apenas tem isso:
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;
}
}
Isso não está realmente documentado, mas faz parte da lib principal e a fonte é direta . Eu o uso há algum tempo, até agora sem problemas, embora admita que não tentei fazer nada complexo envolvendo spannables.
É correto, a melhor maneira de corrigi-lo no próprio layout XML usando:
<EditText
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
como corretamente apontado por Florian Fröhlich, ele funciona bem para exibições de texto.
<TextView
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
Apenas uma palavra de cautela, os caracteres mencionados no android:digits
serão exibidos apenas, portanto, tenha cuidado para não perder nenhum conjunto de caracteres :)
inputType
, não afeta a filtragem.
Essa solução simples funcionou para mim quando eu precisei impedir o usuário de inserir cadeias vazias em um EditText. Obviamente, você pode adicionar mais caracteres:
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});
}
Se você subclassificar InputFilter, poderá criar seu próprio InputFilter que filtraria quaisquer caracteres não alfanuméricos.
A Interface InputFilter possui um método filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
e fornece todas as informações necessárias sobre quais caracteres foram inseridos no EditText ao qual está atribuído.
Depois de criar seu próprio InputFilter, você pode atribuí-lo ao EditText chamando setFilters (...).
http://developer.android.com/reference/android/text/InputFilter.html#filter(java.lang.CharSequence , int, int, android.text.Spanned, int, int)
Ignorando as coisas de extensão com as quais outras pessoas lidaram, para lidar adequadamente com as sugestões de dicionário, achei o seguinte código funcionando.
A fonte cresce à medida que a sugestão aumenta, por isso temos que ver quantos caracteres ele realmente espera que substituamos antes de retornar alguma coisa.
Se não tivermos caracteres inválidos, retorne nulo para que a substituição padrão ocorra.
Caso contrário, precisamos extrair os caracteres válidos da substring que REALMENTE será colocada no 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 impedir palavras no edittext. crie uma classe que você possa usar a qualquer 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;
}
}
Primeiro adicione em strings.xml
:
<string name="vin_code_mask">0123456789abcdefghjklmnprstuvwxyz</string>
XML :
android:digits="@string/vin_code_mask"
Código em 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
}
Estranho, mas funciona estranhamente no teclado virtual do emulador.
Aviso! O código a seguir filtrará todas as letras e outros símbolos, exceto os dígitos dos teclados de software. Somente o teclado digital aparecerá nos smartphones.
edit_text.keyListener = DigitsKeyListener.getInstance(context.getString(R.string.vin_code_mask))
Eu também geralmente fixados maxLength
, filters
, inputType
.
Esse é um tópico antigo, mas as soluções propostas têm problemas (dependendo do dispositivo / versão do Android / teclado).
ABORDAGEM DIFERENTE
Então, eventualmente, eu segui uma abordagem diferente, em vez de usar a InputFilter
implementação problemática, estou usando TextWatcher
e TextChangedListener
a EditText
.
CÓDIGO COMPLETO (EXEMPLO)
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
}
});
O motivo InputFilter
não é uma boa solução no Android, pois depende da implementação do teclado. A entrada do teclado está sendo filtrada antes de ser passada para o EditText
. Porém, como alguns teclados têm implementações diferentes para a InputFilter.filter()
chamada, isso é problemático.
Por outro lado, TextWatcher
não se preocupa com a implementação do teclado, pois permite criar uma solução simples e garantir que funcione em todos os dispositivos.
onTextChanged
simplesmente precisa de um public void
na frente dele.
Fiz algo assim para simplificar:
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 ]"), "")
}
})
Dessa forma, estamos substituindo todos os caracteres indesejados na nova parte da cadeia de origem por uma cadeia vazia.
A edit_text
variável é aEditText
objeto ao qual estamos nos referindo.
O código está escrito kotlin
.
É possível usar setOnKeyListener
. Neste método, podemos personalizar a entrada edittext
!
Foi assim que criei um filtro para o campo Nome em Editar texto. (A primeira letra é CAPS e permite apenas um espaço após cada palavra.
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)});
}
Eu tenho a mesma resposta em 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
}
}
}
e obtenha a classe com a função Extension:
fun EditText.filterByDataType(filterType: Int) {
this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}