Android NumberPicker с Formatter не форматируется при первом рендеринге

У меня есть 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); 

Solutions Collecting From Web of "Android NumberPicker с Formatter не форматируется при первом рендеринге"

Я также столкнулся с этой досадной маленькой ошибкой . Использовал технику из этого ответа, чтобы придумать неприятное, но эффективное исправление.

 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 сразу после создания экземпляра моего changeValueByOne чисел, похоже, достаточно для форматирования, чтобы вести себя так, как нужно. Выбор номера подходит и чист, и первое значение отформатировано правильно. Как я сказал, противно, но эффективно.

Решение dgel не работает для меня: когда я нажимаю на сборщик, форматирование снова исчезает. Эта ошибка вызвана набором входных фильтров на EditText внутри NumberPicker когда setDisplayValues не используется. Поэтому я придумал это решение:

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

У меня была та же проблема, и вместо этого я использовал метод 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) 

Это не позволяет пользователю устанавливать значение вручную в сборщике.

Вызов частного метода changeValueByOne() через отражение, как описано в более раннем ответе, работает для меня на API Level 16 (Android 4.1.2 и выше), но, похоже, он не помогает на API Level 15 (Android 4.0.3), однако !

Что работает для меня на уровне API 15 (и выше), это использовать собственный пользовательский форматтер для создания массива String и передать его с помощью метода setDisplayedValues() в setDisplayedValues() .

См. Также: Android 3.x и 4.x NumberPicker Example

Мне удалось это исправить, позвонив

 picker.invalidate(); 

Сразу после установки форматирования.

Это решение разработало для меня 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 и убедитесь, что события кликов не пройдены, поэтому сбой, когда элементы picker disapear при касании не могут произойти.

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