J'ai un NumberPicker qui a un formateur qui formate les nombres affichés lorsque le NumberPicker tourne ou lorsqu'une valeur est entrée manuellement. Cela fonctionne bien, mais lorsque NumberPicker est affiché pour la première fois et que je l'initialise avec setValue(0)
, le 0 n'est pas formaté (il doit afficher "-" au lieu de 0). Dès que je tourne le NumberPicker à partir de là, tout fonctionne.
Comment puis-je forcer NumberPicker à formater toujours - à la fois lors du premier rendu et aussi lorsque je saisis un nombre manuellement avec le clavier?
C'est mon formateur
public class PickerFormatter implements Formatter {
private String mSingle;
private String mMultiple;
public PickerFormatter(String single, String multiple) {
mSingle = single;
mMultiple = multiple;
}
@Override
public String format(int num) {
if (num == 0) {
return "-";
}
if (num == 1) {
return num + " " + mSingle;
}
return num + " " + mMultiple;
}
}
J'ajoute mon formateur au sélecteur avec setFormatter()
, c'est tout ce que je fais au sélecteur.
picker.setMaxValue(max);
picker.setMinValue(min);
picker.setFormatter(new PickerFormatter(single, multiple));
picker.setWrapSelectorWheel(wrap);
J'ai aussi rencontré ce petit ennuyeux bug . Utilisé une technique de cette réponse pour trouver un correctif vilain mais efficace.
NumberPicker picker = (NumberPicker)view.findViewById(id.picker);
picker.setMinValue(1);
picker.setMaxValue(5);
picker.setWrapSelectorWheel(false);
picker.setFormatter(new NumberPicker.Formatter() {
@Override
public String format(int value) {
return my_formatter(value);
}
});
try {
Method method = picker.getClass().getDeclaredMethod("changeValueByOne", boolean.class);
method.setAccessible(true);
method.invoke(picker, true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
L'appel de cette méthode privée changeValueByOne
immédiatement après l'instanciation de mon sélecteur de numéros semble donner suffisamment de coups au formateur pour qu'il se comporte comme il se doit. Le sélecteur de nombres arrive bien et propre avec la première valeur correctement formatée. Comme je le disais, méchant mais efficace.
La solution de dgel ne fonctionne pas pour moi: lorsque je tape sur le sélecteur, le formatage disparaît à nouveau. Ce bogue est causé par le filtre d'entrée défini sur EditText
dans NumberPicker
lorsque setDisplayValues
n'est pas utilisé. Alors je suis venu avec cette solution de contournement:
Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = (EditText)f.get(mPicker);
inputText.setFilters(new InputFilter[0]);
J'ai eu le même problème et j'ai utilisé la méthode setDisplayedValues()
à la place.
int max = 99;
String[] values = new String[99];
values[0] = “-” + mSingle
values[1] =
for(int i=2; i<=max; i++){
makeNames[i] = String.valueOf(i) + mMultiple;
}
picker.setMinValue(0);
picker.setMaxValue(max);
picker.setDisplayedValues(values)
Cela ne permet toutefois pas à l'utilisateur de définir la valeur manuellement dans le sélecteur.
La solution suivante a fonctionné pour moi pour les API 18-26 sans utiliser la réflexion , et sans utiliser setDisplayedValues()
.
Il se compose de deux étapes:
Assurez-vous que le premier élément s'affiche en définissant sa visibilité sur invisible (j'ai utilisé Inspecteur de disposition pour voir la différence par rapport à l'affichage, ce n'est pas logique, mais View.INVISIBLE
rend la vue visible).
private void initNumberPicker() {
// Inflate or create your BugFixNumberPicker class
// Do your initialization on bugFixNumberPicker...
bugFixNumberPicker.setFormatter(new NumberPicker.Formatter() {
@Override
public String format(final int value) {
// Format to your needs
return aFormatMethod(value);
}
});
// Fix for bug in Android Picker where the first element is not shown
View firstItem = bugFixNumberPicker.getChildAt(0);
if (firstItem != null) {
firstItem.setVisibility(View.INVISIBLE);
}
}
Sous-classe NumberPicker et assurez-vous qu'aucun événement de clic ne survient afin d'éviter tout problème lié à la disparition d'éléments de sélecteur au toucher.
public class BugFixNumberPicker extends NumberPicker {
public BugFixNumberPicker(Context context) {
super(context);
}
public BugFixNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BugFixNumberPicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean performClick() {
return false;
}
@Override
public boolean performLongClick() {
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return false;
}
}
L'appel de la méthode privée changeValueByOne()
par réflexion comme décrit dans une réponse précédente fonctionne pour moi sur API Level 16
(Android 4.1.2 et versions ultérieures), mais cela ne semble pas aider pour API Level 15
(Android 4.0.3)!
Ce qui fonctionne pour moi à l’API de niveau 15 (et supérieur) est d’utiliser votre propre formateur personnalisé pour créer un tableau de chaînes et de le transmettre avec la méthode setDisplayedValues()
au sélecteur de nombres.
Voir aussi: Exemple pour NumberPicker sous Android 3.x et 4.x
La réponse fournie par NoActivity a fonctionné pour moi, mais je n'avais qu'à faire:
View firstItem = bugFixNumberPicker.getChildAt(0);
if (firstItem != null) {
firstItem.setVisibility(View.INVISIBLE);
}
pour résoudre le problème. Je n'ai pas eu besoin de sous-classe NumberPicker. Je n'ai pas vu le problème où les éléments de sélecteur disparaissent au toucher.
J'ai réussi à le réparer en appelant
picker.invalidate();
juste après le réglage du formateur.
Voici ma solution basée sur les réponses de torvin et Sebastian . Vous n'avez rien à sous-classer ou à utiliser la réflexion.
View editView = numberPicker.getChildAt(0);
if (editView != null && editView instanceof EditText) {
// Remove default input filter
((EditText) editView).setFilters(new InputFilter[0]);
}