带有Formatter的Android NumberPicker在首次渲染时不会格式化

时间:2013-07-17 19:15:07

标签: android formatter numberpicker android-number-picker

我有一个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);

10 个答案:

答案 0 :(得分:25)

我也遇到了这个烦人的小bug。使用this answer中的一种技术来提出令人讨厌但有效的修复方法。

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方法似乎足以使格式化程序表现得如此。数字选择器出现很好,干净,第一个值格式正确。就像我说的那样,讨厌但有效。

答案 1 :(得分:25)

dgel's solution对我不起作用:当我点击选择器时,格式化会再次消失。如果未使用EditText,则NumberPicker内的setDisplayValues上设置的输入过滤器会导致此错误。所以我提出了这个解决方法:

Field f = NumberPicker.class.getDeclaredField("mInputText");
f.setAccessible(true);
EditText inputText = (EditText)f.get(mPicker);
inputText.setFilters(new InputFilter[0]);

答案 2 :(得分:11)

我遇到了同样的问题而我使用了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)

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

答案 3 :(得分:5)

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

它包含两个步骤:

  1. 通过将第一个元素的可见性设置为不可见来确保显示第一个元素(我使用布局检查器查看显示时间的差异,它不符合逻辑,但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); } } 使视图可见。

    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;
     }
    }
    
  2. Subclass NumberPicker并确保没有点击事件通过,因此拾取元素在触摸时消失的故障不会发生。

     $conn = mysqli_connect("localhost", "root", "", "databasename");
    

答案 4 :(得分:4)

如前面的回答中所述,通过反射调用私有方法changeValueByOne()适用于API Level 16(Android 4.1.2及更高版本),但它似乎对{{1}没有帮助但是(Android 4.0.3)!

在API级别15(及以上)对我有用的是使用您自己的自定义格式化程序来创建String数组,并使用方法API Level 15将其传递给数字选择器。

另请参阅:Android 3.x and 4.x NumberPicker Example

答案 5 :(得分:3)

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

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

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

答案 6 :(得分:3)

这是我基于torvinSebastian的答案的解决方案。您不必继承任何子类或使用反射。

View editView = numberPicker.getChildAt(0);

if (editView != null && editView instanceof EditText) {
    // Remove default input filter
    ((EditText) editView).setFilters(new InputFilter[0]);
}

答案 7 :(得分:1)

我设法通过调用

来修复它
picker.invalidate();

设置格式化程序后。

答案 8 :(得分:1)

Kotlin 版本基于 Nikolai's 答案

private fun initNumberPicker() {
    nrPicker.children.iterator().forEach {
        if (it is EditText) it.filters = arrayOfNulls(0)    // remove default input filter
    }
}

答案 9 :(得分: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)
        }
    }