Android NumberPicker with Formatter doesn't fo

2019-01-11 06:01发布

I have a NumberPicker that has a formatter that formats the displayed numbers either when the NumberPicker spins or when a value is entered manually. This works fine, but when the NumberPicker is first shown and I initialize it with setValue(0) the 0 does not get formatted (it should display as "-" instead of 0). As soon as I spin the NumberPicker from that point on everything works.

How can I force the NumberPicker to format always - Both on first rendering and also when I enter a number manually with 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 picker with setFormatter(), this is all I do to the picker.

    picker.setMaxValue(max);
    picker.setMinValue(min);
    picker.setFormatter(new PickerFormatter(single, multiple));
    picker.setWrapSelectorWheel(wrap);

8条回答
Emotional °昔
2楼-- · 2019-01-11 06:43

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

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 doesn't allow the user to set the value manually in the picker though.

查看更多
戒情不戒烟
3楼-- · 2019-01-11 06:44

Here's my solution based on answers by torvin and Sebastian. You don't have to subclass anything or use reflection.

View editView = numberPicker.getChildAt(0);

if (editView != null && editView instanceof EditText) {
    // Remove default input filter
    ((EditText) editView).setFilters(new InputFilter[0]);
}
查看更多
霸刀☆藐视天下
4楼-- · 2019-01-11 06:47

dgel's solution doesn't work for me: when I tap on the picker, formatting disappears again. This bug is caused by input filter set on EditText inside NumberPicker when setDisplayValues isn't used. So I came up with this workaround:

Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = (EditText)f.get(mPicker);
inputText.setFilters(new InputFilter[0]);
查看更多
Luminary・发光体
5楼-- · 2019-01-11 06:51

The following solution worked out for me for APIs 18-26 without using reflection, and without using setDisplayedValues().

It consists of two steps:

  1. Make sure the first element shows by setting it's visibility to invisible (I used Layout Inspector to see the difference with when it shows, it's not logical but View.INVISIBLE actually 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);
      }
    }
    
  2. Subclass NumberPicker and make sure no click events go through so the glitch where picker elements disapear on touch can't 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;
     }
    }
    
查看更多
老娘就宠你
6楼-- · 2019-01-11 06:55

I managed to fix it by calling

picker.invalidate();

just after setting the formatter.

查看更多
戒情不戒烟
7楼-- · 2019-01-11 07:01

Calling the private method changeValueByOne() via reflection as described in an earlier answer works for me on API Level 16 (Android 4.1.2 and up), but it does not seem to help on API Level 15 (Android 4.0.3), however!

What works for me on API Level 15 (and up) is to use your own custom formatter to create String array and pass that with the method setDisplayedValues() to the number picker.

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

查看更多
登录 后发表回答