Réponses:
J'ai trouvé ça sur un autre forum. Fonctionne comme un champion.
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
Les versions d'Android qui affichent des suggestions de dictionnaires sont un peu compliquées. Vous obtenez parfois un SpannableStringBuilder
, parfois un simple String
dans le source
paramètre.
Ce qui suit InputFilter
devrait fonctionner. N'hésitez pas à améliorer ce code!
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
entrer AB me donne AAB comme lorsque j'essaye la réponse précédente. Heureusement, j'ai pu contourner ce problème en utilisant la solution @florian ci-dessous.
beaucoup plus facile:
<EditText
android:inputType="text"
android:digits="0,1,2,3,4,5,6,7,8,9,*,qwertzuiopasdfghjklyxcvbnm" />
","
entre les deux. Vous pouvez utiliser quelque chose comme ça"0123456789qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"
imeOptions="actionNext"
, etc.
Aucune des réponses publiées n'a fonctionné pour moi. Je suis venu avec ma propre solution:
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
peut déjà avoir ses propres filtres, par exemple un filtre de longueur. Ainsi, au lieu de simplement remplacer les filtres, vous souhaiterez probablement ajouter vos filtres à ceux déjà existants.
Utilisez ce travail à 100% selon vos besoins et très simple.
<EditText
android:inputType="textFilter"
android:digits="@string/myAlphaNumeric" />
Dans strings.xml
<string name="myAlphaNumeric">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</string>
Pour éviter les caractères spéciaux dans le type d'entrée
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;
}
};
Vous pouvez définir un filtre sur votre texte d'édition comme ci-dessous
edtText.setFilters(new InputFilter[] { filter });
En plus de la réponse acceptée, il est également possible d'utiliser par exemple: android:inputType="textCapCharacters"
comme attribut de <EditText>
pour n'accepter que les majuscules (et les nombres).
Pour une raison quelconque, le constructeur de la classe android.text.LoginFilter a une portée globale, vous ne pouvez donc pas l'étendre directement (même s'il serait identique à ce code). Mais vous pouvez étendre LoginFilter.UsernameFilterGeneric! Ensuite, vous avez juste ceci:
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;
}
}
Ce n'est pas vraiment documenté, mais cela fait partie de la bibliothèque principale, et la source est simple . Je l'utilise depuis un moment maintenant, jusqu'à présent aucun problème, même si j'avoue que je n'ai pas essayé de faire quelque chose de complexe impliquant des spannables.
C'est vrai, la meilleure façon de procéder pour le corriger dans la mise en page XML elle-même en utilisant:
<EditText
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
comme l'a justement souligné Florian Fröhlich, cela fonctionne bien pour les vues de texte même.
<TextView
android:inputType="text"
android:digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" />
Juste un mot d'avertissement, les caractères mentionnés dans le android:digits
seront uniquement affichés, alors faites attention à ne manquer aucun jeu de caractères :)
inputType
cela n'affecte pas le filtrage.
Cette solution simple a fonctionné pour moi lorsque je devais empêcher l'utilisateur d'entrer des chaînes vides dans un EditText. Vous pouvez bien sûr ajouter plus de caractères:
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 vous sous-classez InputFilter, vous pouvez créer votre propre InputFilter qui filtrerait tous les caractères non alphanumériques.
L'interface InputFilter a une méthode, filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
et elle vous fournit toutes les informations dont vous avez besoin pour savoir quels caractères ont été entrés dans le EditText auquel il est affecté.
Une fois que vous avez créé votre propre InputFilter, vous pouvez l'attribuer à EditText en appelant setFilters (...).
http://developer.android.com/reference/android/text/InputFilter.html#filter(java.lang.CharSequence , int, int, android.text.Spanned, int, int)
En ignorant les problèmes de span que d'autres personnes ont traités, pour gérer correctement les suggestions de dictionnaire, j'ai trouvé que le code suivant fonctionne.
La source grandit au fur et à mesure que la suggestion grandit, nous devons donc examiner le nombre de caractères que nous attendons réellement de nous remplacer avant de retourner quoi que ce soit.
Si nous n'avons pas de caractères non valides, retournez null pour que le remplacement par défaut se produise.
Sinon, nous devons extraire les caractères valides de la sous-chaîne qui va VRAIMENT être placée dans 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;
}
};
pour empêcher les mots dans edittext. créez une classe que vous pourriez utiliser à tout moment.
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;
}
}
Ajoutez d'abord dans strings.xml
:
<string name="vin_code_mask">0123456789abcdefghjklmnprstuvwxyz</string>
XML :
android:digits="@string/vin_code_mask"
Code 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
}
Étrange, mais cela fonctionne bizarrement sur le clavier virtuel de l'émulateur.
Avertissement! Le code suivant filtrera toutes les lettres et autres symboles à l'exception des chiffres des claviers logiciels. Seul le clavier numérique apparaîtra sur les smartphones.
edit_text.keyListener = DigitsKeyListener.getInstance(context.getString(R.string.vin_code_mask))
Je habituellement également mis maxLength
, filters
, inputType
.
Il s'agit d'un ancien fil de discussion, mais les solutions proposées ont toutes des problèmes (selon l'appareil / la version Android / le clavier).
UNE APPROCHE DIFFÉRENTE
Donc, finalement, je suis allé avec une approche différente, au lieu d'utiliser l' InputFilter
implémentation problématique, j'utilise TextWatcher
et TextChangedListener
le EditText
.
CODE COMPLET (EXEMPLE)
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 raison InputFilter
n'est pas une bonne solution sous Android car cela dépend de l'implémentation du clavier. L'entrée Clavier est filtrée avant que l'entrée ne soit transmise au EditText
. Mais, comme certains claviers ont des implémentations différentes pour l' InputFilter.filter()
invocation, cela est problématique.
D'autre part, TextWatcher
ne se soucie pas de l'implémentation du clavier, cela nous permet de créer une solution simple et d'être sûr qu'elle fonctionnera sur tous les appareils.
onTextChanged
simplement besoin d'un public void
devant lui.
J'ai fait quelque chose comme ça pour rester 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 cette façon, nous remplaçons tous les caractères indésirables dans la nouvelle partie de la chaîne source par une chaîne vide.
La edit_text
variable est l' EditText
objet auquel nous nous référons.
Le code est écrit kotlin
.
Il est possible d'utiliser setOnKeyListener
. Dans cette méthode, nous pouvons personnaliser l'entrée edittext
!
C'est ainsi que j'ai créé un filtre pour le champ Nom dans Modifier le texte (la première lettre est MAJUSCULES et n'autorise qu'un seul espace après chaque mot.
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)});
}
J'ai la même réponse à 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
}
}
}
et récupérez la classe avec une fonction d'extension:
fun EditText.filterByDataType(filterType: Int) {
this.filters = arrayOf<InputFilter>(InputFilterAlphanumeric(filterType))
}