【问题标题】:Android NumberPicker with Formatter doesn't format on first rendering带有 Formatter 的 Android NumberPicker 在第一次渲染时不格式化
【发布时间】:2013-07-16 12:14:25
【问题描述】:

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

【问题讨论】:

  • 能否发一些代码,有助于回答。
  • 它只是一个标准实现,真的:
  • 添加了一些代码,但代码不是问题,数字选择器只是在第一次渲染时不执行代码
  • 我对此有点新,但你能从构造函数中调用 format() 吗?我不认为它最初被调用。这会有帮助吗?
  • 我刚刚google了一下,在Android项目上发现了这个问题报告:code.google.com/p/android/issues/detail?id=35482让我们等待修复。

标签: android formatter numberpicker android-number-picker


【解决方案1】:

基于Nikolai's答案的Kotlin版本

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

【讨论】:

    【解决方案2】:

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

    View editView = numberPicker.getChildAt(0);
    
    if (editView instanceof EditText) {
        // Remove default input filter
        ((EditText) editView).setFilters(new InputFilter[0]);
    }
    

    【讨论】:

    • 感谢这个解决方案,这对我有用,它使用数据绑定、数字选择器和格式化程序,还包括 unicode 符号。
    【解决方案3】:

    如果所选索引不为 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)
            }
        }
    

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 我可以确认格式化的元素在触摸时消失(在 Lollipop 上测试)。
      【解决方案5】:

      以下解决方案适用于 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;
         }
        }
        

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

        • 在 API 25 上为我工作。谢谢!
        【解决方案7】:

        我设法通过调用来修复它

        picker.invalidate();
        

        在设置格式化程序之后。

        【讨论】:

          【解决方案8】:

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

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

          【讨论】:

          • 来自Android Developer Reference:注意:通过 setDisplayedValues(String[]) 设置的显示值数组的长度必须等于可选数字的范围,即 getMaxValue() - getMinValue( ) + 1.
          【解决方案9】:

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

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

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

          【讨论】:

            【解决方案10】:

            我也遇到过这个烦人的小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 方法似乎足以使格式化程序发挥应有的作用。数字选择器很干净,第一个值的格式正确。就像我说的,讨厌但有效。

            【讨论】:

            • 不知何故,在 Android 编程中,您必须经常使用讨厌的 hack。
            • 这个 bug 是在 2 年前报告的……你在开玩笑吧 google?在 android 4.4.2 上仍然是一个问题
            • 确实 - 这仍然存在于棉花糖中 :(
            • Android 7.1.1 并且该错误似乎仍然完全未被注意到。
            • 埃隆马斯克向太空发射了一辆特斯拉,但这个问题仍然存在。
            猜你喜欢
            • 2019-10-24
            • 1970-01-01
            • 2020-08-25
            • 1970-01-01
            • 2023-01-14
            • 2021-06-04
            • 2021-08-12
            • 2017-04-02
            • 2017-06-04
            相关资源
            最近更新 更多