web-dev-qa-db-fra.com

Android NumberPicker avec Formatter ne formate pas lors du premier rendu

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);
29
A. Steenbergen

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.

24
dgel

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]);
22
torvin

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.

10
Lumbi

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:

  1. 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);
      }
    }
    
  2. 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;
     }
    }
    
5
Sebastian

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

3
HeNRGi

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.

3
Christopher Chua

J'ai réussi à le réparer en appelant

picker.invalidate();

juste après le réglage du formateur.

1
user1504495

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]);
}
1
Nikolai