38

我有一个 NumberPicker,它有一个格式化程序,可以在 NumberPicker 旋转或手动输入值时格式化显示的数字。这工作正常,但是当 NumberPicker 首次显示并且我用setValue(0)0 初始化它时没有格式化(它应该显示为“-”而不是 0)。一旦我从那一刻开始旋转 NumberPicker,一切正常。

如何强制 NumberPicker 始终格式化 - 无论是在第一次渲染时还是在我使用键盘手动输入数字时?

这是我的格式化程序

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

}

我用 将我的格式化程序添加到选择器中setFormatter(),这就是我对选择器所做的一切。

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

10 回答 10

29

dgel 的解决方案对我不起作用:当我点击选择器时,格式再次消失。此错误是由未使用时设置在EditText内部的输入过滤器引起的。所以我想出了这个解决方法:NumberPickersetDisplayValues

Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = (EditText)f.get(mPicker);
inputText.setFilters(new InputFilter[0]);
于 2014-11-07T09:12:03.227 回答
27

我也遇到了这个烦人的小bug。使用此答案中的一种技术提出了一个令人讨厌但有效的解决方案。

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

在实例化我的号码选择器后立即调用该私有changeValueByOne方法似乎足以使格式化程序发挥应有的作用。数字选择器很干净,第一个值的格式正确。就像我说的,讨厌但有效。

于 2013-09-30T21:20:39.603 回答
12

我有同样的问题,我使用了这个setDisplayedValues()方法。

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)

但是,这不允许用户在选择器中手动设置值。

于 2014-03-04T21:59:11.853 回答
7

以下解决方案适用于 API 18-26 ,不使用反射,也不使用setDisplayedValues().

它由两个步骤组成:

  1. 通过将第一个元素的可见性设置为不可见来确保显示第一个元素(我使用 Layout Inspector 来查看它显示时的差异,这不合逻辑但View.INVISIBLE实际上使视图可见)。

    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. 子类 NumberPicker 并确保没有点击事件通过,这样选择器元素在触摸时消失的故障就不会发生。

    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;
     }
    }
    
于 2017-07-06T12:35:54.507 回答
6

这是我根据torvinSebastian的回答提出的解决方案。您不必继承任何东西或使用反射。

View editView = numberPicker.getChildAt(0);

if (editView instanceof EditText) {
    // Remove default input filter
    ((EditText) editView).setFilters(new InputFilter[0]);
}
于 2019-01-07T23:18:51.993 回答
4

changeValueByOne()如先前答案中所述,通过反射调用私有方法对我API Level 16有用(Android 4.1.2 及更高版本),但它似乎对API Level 15(Android 4.0.3)没有帮助!

在 API 级别 15(及更高级别)上对我有用的是使用您自己的自定义格式化程序来创建字符串数组并将其与方法一起传递setDisplayedValues()给数字选择器。

另请参阅:Android 3.x 和 4.x NumberPicker 示例

于 2013-12-11T18:41:00.670 回答
4

NoActivity 提供的答案对我有用,但我只需要这样做:

View firstItem = bugFixNumberPicker.getChildAt(0);
if (firstItem != null) {
  firstItem.setVisibility(View.INVISIBLE);
}

解决问题。我不需要继承 NumberPicker。我没有看到选择器元素在触摸时消失的问题。

于 2018-05-29T23:31:42.933 回答
2

Kotlin 版本基于Nikolai 的回答

private fun initNumberPicker() {
    nrPicker.children.iterator().forEach {
        if (it is EditText) it.filters = arrayOfNulls(0)    // remove default input filter
    }
}
于 2021-01-06T21:01:23.667 回答
1

我设法通过调用来修复它

picker.invalidate();

就在设置格式化程序之后。

于 2014-11-04T12:00:20.473 回答
0

如果所选索引不为 0,则改进 Nikolai 答案。对性能来说不是很好,但可以解决问题..

for(index in numberPicker.minValue..numberPicker.maxValue) {

        val editView = numberPicker.getChildAt(index-numberPicker.minValue)
        if (editView != null && editView is EditText) {
            // Remove default input filter
            (editView as EditText).filters = arrayOfNulls(0)
        }
    }
于 2019-10-25T19:16:27.337 回答