2013-07-17 4 views
22

У меня есть NumberPicker, у которого есть форматировщик, который форматирует отображаемые числа либо при вращении NumPicker, либо при вводе значения вручную. Это отлично работает, но когда сначала отображается NumberPicker и я инициализирую его setValue(0), 0 не форматируется (он должен отображаться как «-» вместо 0). Как только я вращаю NumberPicker с этого момента, все работает.Android NumberPicker с Formatter не форматируется при первом рендеринге

Как я могу принудительно форматировать 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); 
+0

Не могли бы вы опубликовать код, он помогает ответить. –

+0

его просто стандартная реализация, действительно: –

+0

добавил некоторый код, но код не является проблемой, numberpicker просто не выполняет код на первом рендере –

ответ

19

Я также столкнулся с этим раздражающим маленьким 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(); 
} 

Calling, что частный changeValueByOne метод сразу же после того, как инстанцировании мой номер сборщика кажется пинать форматировщик достаточно, чтобы вести себя, как это должно быть. Выбор номера подходит и чист, при этом первое значение отформатировано правильно. Как я сказал, противно, но эффективно.

+5

Как-то в Android-программировании вы часто используете неприятные хаки. –

+1

не может поверить, что это еще не исправлено. –

+3

эта ошибка была сообщена 2 года назад ... вы издеваетесь за меня google? все еще проблема на android 4.4.2 – serine

3

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

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

Смотрите также: Android 3.x and 4.x NumberPicker Example

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) 

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

1

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

picker.invalidate(); 

только после установки форматировщик.

14

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]); 
+1

Работал для меня по API 25. Спасибо! – nope4561759

1

следующее решение разработаны для меня 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); 
        } 
    } 
    
  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; 
    } 
    }