Android NumberPicker with Formatter is not formatted on first render

I have a NumberPicker that has a formatter that formats the displayed numbers either by rotating the NumberPicker or by manually entering a value. This works fine, but when NumberPicker is displayed first, and I initialize it with setValue(0) , 0 is not formatted (it should display as "-" instead of 0). As soon as I rotate NumberPicker from now on, everything works.

How can I force NumberPicker to be formatted - both during the first rendering and when manually entering a number from the keyboard?

This is my formatter

 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; } } 

I add my formatter to the collector using setFormatter() , that's all I do for the collector.

  picker.setMaxValue(max); picker.setMinValue(min); picker.setFormatter(new PickerFormatter(single, multiple)); picker.setWrapSelectorWheel(wrap); 
+21
android numberpicker formatter android-number-picker
Jul 17 '13 at 19:15
source share
6 answers

I also came across this annoying little mistake . Used the technique from this answer to come up with an unpleasant but effective fix.

 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(); } 

Calling this private method changeValueByOne immediately after instantiating my set of numbers seems to result in formatting sufficient to behave as it should. The choice of number is appropriate and clean, while the first value is formatted correctly. As I said, nasty but effective.

+18
Sep 30 '13 at 21:20
source share

dgel solution does not work for me: when I click on the collector, the formatting disappears again. This error is caused by setting the input filter to EditText inside NumberPicker when setDisplayValues not used. So I came up with this solution:

 Field f = NumberPicker.class.getDeclaredField("mInputText"); f.setAccessible(true); EditText inputText = (EditText)f.get(mPicker); inputText.setFilters(new InputFilter[0]); 
+14
Nov 07 '14 at 9:12
source share

I had the same problem and instead used the setDisplayedValues() method.

 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) 

This prevents the user from manually setting the value in the collector.

+8
Mar 04 '14 at 21:59
source share

Calling the private changeValueByOne() method through reflection, as described in an earlier answer, works for me on API Level 16 (Android 4.1.2 and above), but it doesn't seem to help on API Level 15 (Android 4.0.3). However!

What works for me at API level 15 (and above) is to use my own custom formatter to create a String array and pass it using the setDisplayedValues() method to the number picker.

See also: Android 3.x and 4.x NumberPicker Example

+3
Dec 11 '13 at 18:41
source share

I managed to fix it by calling

 picker.invalidate(); 

immediately after setting the formatting.

+1
Nov 04 '14 at 12:00
source share

This solution developed API 18-26 for me without using reflection and without using setDisplayedValues() .

It consists of two steps:

  • Make sure that the first element is displayed by setting its visibility invisible (I used the "Layout inspector" to see the difference when it shows, it is not logical, but View.INVISIBLE really makes the view 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); } } 
  • Subclass NumberPicker and make sure no click events go through, so a crash where pickups disappear when touched cannot happen.

     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; } } 
0
Jul 6 '17 at 12:35
source share



All Articles