NumberPicker не работает с клавиатурой

In activity_main.xml :

<NumberPicker
        android:id="@+id/numberPicker1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView2"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="30dp" />

В MainActivity.java внутри oncreate :

NumberPicker numberPicker1 = (NumberPicker) findViewById(R.id.numberPicker1);
numberPicker1.setMinValue(1);
numberPicker1.setMaxValue(20);

Когда я редактирую значение с помощью клавиатуры, значение, которое я получаю программно, не меняется, но если я нажимаю +, то - оно работает.

Как я могу заставить его работать, не нажимая + и -?


ИЗМЕНИТЬ:

Я создал новый проект с кодом Мелиха Алтынташа, и он отобразил совершенно новый набор чисел!! (Тот, где вы проводите пальцем и не можете ввести текст). Потом я сравнил со своим реальным проектом и увидел android:theme="@android:style/Theme.NoTitleBar". Я добавил его в новый проект, и тогда числовик стал тем, к которому я привык.


person Mageek    schedule 22.09.2013    source источник
comment
У меня такая же проблема, кто-нибудь придумал лучший ответ на это, возможно?   -  person Alan Moore    schedule 17.10.2013


Ответы (6)


NumberPicker не был предназначен для такого взаимодействия. Когда вы меняете значение с помощью клавиатуры, вы вносите изменения непосредственно в виджет из NumberPicker, и сам виджет не видит этого изменения, поэтому вы получаете последнее сохраненное значение. Чтобы обойти это, вам понадобится какой-то хакерский код, который на самом деле не рекомендуется, потому что вам потребуется доступ к базовому EditText (при условии, что производитель телефона не изменил это в первую очередь):

private EditText findInput(ViewGroup np) {
    int count = np.getChildCount();
    for (int i = 0; i < count; i++) {
        final View child = np.getChildAt(i);
        if (child instanceof ViewGroup) {
            findInput((ViewGroup) child);
        } else if (child instanceof EditText) {
            return (EditText) child;
        }
    }
    return null;
}

а затем вы будете использовать этот код, чтобы установить TextWatcher для найденного EditText, чтобы увидеть, когда он был изменен вручную (и сообщить NumberPicker об этом изменении):

EditText input = findInput(np);    
TextWatcher tw = new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {}

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {}

        @Override
        public void afterTextChanged(Editable s) {
                if (s.toString().length() != 0) {
                    Integer value = Integer.parseInt(s.toString());
                    if (value >= np.getMinValue()) {
                        np.setValue(value);
                    }
                }
        }
    };
input.addTextChangedListener(tw);

Другой вариант — сделать собственную реализацию виджета NumberPicker и вставить нужные функции.

person user    schedule 24.09.2013
comment
Вы проверили это? Я имею в виду, ты уверен, что это должно работать? Потому что это приводит к сбою моего приложения с помощью Invalid int: "". (Кстати, я переместил input.addTextChangedListener(tw); вниз, потому что tw не будет определен) - person Mageek; 24.09.2013
comment
@Mageek Строка np.setValue(Integer.parseInt(s.toString())); должна быть обернута проверкой, чтобы убедиться, что строка не пуста (например, когда вы удаляете все числа): if (s.toString().length() == 0) { np.setValue().getMinValue(); } else {np.setValue(Integer.parseInt(s.toString()));} - person user; 24.09.2013
comment
Вы уверены, что это np.setValue().getMinValue(); ? Потому что аргумента нет... (Извините, я еще новичок в программировании на java и android) - person Mageek; 24.09.2013
comment
@Mageek Нет, моя ошибка. Идея заключалась в том, чтобы установить минимальное значение, когда текст будет пустым: np.setValue(np.getMinValue());. - person user; 24.09.2013
comment
Но теперь отредактировать номер становится практически невозможно. Пример: это 7, и вы хотите поставить 2. Сначала стираешь Backspace и PAF становится 1... - person Mageek; 24.09.2013
comment
У меня была идея поместить Integer.parseInt(s.toString()) во временную переменную. А затем используйте эту переменную, чтобы получить значение, но она падает, когда я стираю... - person Mageek; 24.09.2013
comment
@Mageek Я сказал установить NumberPicker на минимальное значение, чтобы у вас не было пустого NumberPicker. Вы всегда можете использовать это в afterTextChanged() методе if (s.toString.length() != 0) {np.setValue(Integer.parseInt(s.toString()));}, просто я не знаю, насколько хорошо это пойдет. - person user; 24.09.2013
comment
Я говорю, что при этом в тот момент, когда вы нажимаете клавишу Backspace, она становится 1. (Вместо "") Таким образом, вы никогда не сможете, например, установить 5, потому что когда вы стираете предыдущее значение, оно становится 1, затем вы пытаетесь стереть 1, и оно остается. - person Mageek; 24.09.2013
comment
@Mageek К сожалению, я не могу сейчас проверить то, что я сказал, но код должен работать. Для ясности я отредактировал свой ответ о том, как должен выглядеть код. Я посмотрю завтра с некоторыми тестами. - person user; 24.09.2013
comment
О, я подумал, что мне следует ДОБАВИТЬ if (s.toString.length() != 0) {np.setValue(Integer.parseInt(s.toString()));} вместо того, чтобы заменить его. Теперь намного лучше! Но есть еще проблема, это если я ставлю например 4 как минимум и 20 как максимум, а число 17 а я хочу поставить 13; Я стираю 7, а потом становится 20 (потому что 1‹4). - person Mageek; 24.09.2013
comment
@Mageek Я видел это. Как и в случае с пустой строкой, вы можете наложить еще одно ограничение, поэтому вы будете устанавливать значение NumberPicker, когда оно как минимум равно минимальному минимальному значению NumberPicker. Я снова отредактировал свой ответ с этим ограничением. Имейте в виду, что с новым кодом, если вы введете значение ниже минимального ограничения, NumberPicker не перейдет к максимальному значению, но также получение значения будет указывать на последнее сохраненное значение (например, если у вас есть 17 и удалено 7, попытка получить значение, пока отображается 1, все равно будет указывать на 17, поскольку NumberPicker еще не обновлено). - person user; 25.09.2013

Если кому-то нужен простой обходной путь, просто добавьте приведенный ниже код перед сохранением значения.

numberPicker.clearFocus();
person 1HaKr    schedule 21.03.2014
comment
ИМО, это самое простое и самое лучшее решение: оно работает. - person Andy Brown; 04.04.2015
comment
Ты настоящий MVP - person mariozawa; 11.01.2018

Я вижу, что у вас уже есть ответ, однако он может быть полезен другим. Вы можете расширить android.widget.NumberPicker и создать свой собственный, где вы можете настроить EditText. Когда вы печатаете на виртуальной клавиатуре, значение вашего NumberPicker сразу же устанавливается на значение, которое вы печатаете.

public class MyNumberPicker extends android.widget.NumberPicker {

       private EditText eText;

       public MyNumberPicker(Context context, AttributeSet attrs) {
        super(context, attrs);
       }


       @Override
       public void addView(View child) {
         super.addView(child);
         initEditText(child);
       }

       @Override
       public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
         super.addView(child, index, params);
         initEditText(child);
       }

       @Override
       public void addView(View child, android.view.ViewGroup.LayoutParams params) {
         super.addView(child, params);
         initEditText(child);
       }

       public void initEditText(View view){
           if(view instanceof EditText){
               EditText eText = (EditText) view;
               eText.addTextChangedListener(new TextWatcher(){

                @Override
                public void afterTextChanged(Editable arg0) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void beforeTextChanged(CharSequence arg0, int arg1,
                        int arg2, int arg3) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    try{
                        int num = Integer.parseInt(s.toString());
                        setValue(num); //this line changes the value of your numberpicker
                    }catch(NumberFormatException E){
                            //do your catching here
                    }   
                }});     
             }
          }
     }

В свой XML-файл вы помещаете следующее:

<com.mypackage.MyNumberPicker
 android:id="@+id/numberPicker1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" />
person Frank D.    schedule 02.04.2014

Вы должны нажать кнопку Done для программного изменения значения.

person Razgriz    schedule 22.09.2013
comment
мой работает сейчас, поэтому, если у вас есть слушатель, который нажимает положительную кнопку, если вы нажимаете четкий фокус, это должно работать. На данном этапе есть два предположения. Почему это работает, потому что предполагается, что вы уже ввели текст, и когда вы вызываете clearFocus во внутренней реализации этого метода, получите значение и установите его во внутреннем редакторе выбора номера. - person Alex Goja; 15.04.2016

причина, по которой это не работает, заключается в том, что если вы посмотрите на реализацию setValue в NumberPicker, она вызовет другой метод setValueInternal (int, boolean), который принимает 2 параметра: новое значение и, конечно, логическое значение bugger, которое представляет, следует ли уведомлять пользовательский интерфейс о любых изменениях или нет. И угадайте, что в setValue логическое значение всегда идет с ложью. черт возьми. Но есть еще один трюк, который я вижу: validateInputTextView на самом деле делает это правильно и вызывается, когда редактируемый текст не имеет фокуса. возможно, в нужный момент очистка фокуса сделает то, что должна делать.

person Alex Goja    schedule 14.04.2016

person    schedule
comment
Я только что нашел что-то действительно странное, смотрите мое редактирование. Вы знаете, что делать? - person Mageek; 22.09.2013
comment
Это странно. android:theme=@android:style/Theme.Light.NoTitleBar связан с панелью состояния. Если вы хотите удалить строку состояния, используйте ее. - person Melih Altıntaş; 22.09.2013
comment
Я решил попробовать этот подход, имея ту же проблему, что описана в вопросе. К сожалению, это, похоже, не имеет никакого значения, средство выбора номеров по-прежнему отображается точно так же и делает то же самое. Я не использую тему, которую упоминает @Mageek, очень странно. Может ли кто-нибудь предложить дополнительную информацию об этом? - person Alan Moore; 17.10.2013