4

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" />

In MainActivity.java inside the oncreate :

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

When I edit the value with the keyboard, the value that I get programmatically doesn't change, but if I press + then - it works.

How can I make it work without having to press + and -?


EDIT :

I created a new Project with the code of Melih Altıntaş and it displayed a whole new numberpicker!! (The one where you slide with your finger and can't enter text). Then I compared with my real project and I saw android:theme="@android:style/Theme.NoTitleBar". I added it in the new project and then the numberpicker became the one I was used to.

Alexandre Khoury
  • 3,896
  • 5
  • 37
  • 58

6 Answers6

20

If anyone wants a simple workaround, just add the below code before saving the value.

numberPicker.clearFocus();
1HaKr
  • 1,098
  • 1
  • 11
  • 18
9

The NumberPicker wasn't designed for that interaction. When you change the value with the keyboard you're making changes directly to a widget from the NumberPicker and the widget itself doesn't see this change so this is why you end up with the last stored value. To get around this you'll need some hacky code, which isn't really recommended, because you'll need to access the underlying EditText(assuming that the phone maker didn't changed this in the first place):

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

and then you'll use this code to set a TextWatcher on the found EditText to see when it's manually modified(and let the NumberPicker know about this change):

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

Another option would be to make your own implementation of the NumberPicker widget and insert the functionality you target.

dsh
  • 12,037
  • 3
  • 33
  • 51
user
  • 86,916
  • 18
  • 197
  • 190
  • Have you tested it? I mean, are you sure it must work? Because it crashes my app with `Invalid int: ""`. (Btw, I moved `input.addTextChangedListener(tw);` to the bottom because tw would not be defined) – Alexandre Khoury Sep 24 '13 at 17:19
  • @Mageek The line `np.setValue(Integer.parseInt(s.toString()));` should be wrapped in a check to see if the String is not empty(like when you delete all the numbers): `if (s.toString().length() == 0) { np.setValue().getMinValue(); } else {np.setValue(Integer.parseInt(s.toString()));}` – user Sep 24 '13 at 17:26
  • Are you sure it's `np.setValue().getMinValue();` ? Because there is no argument... (Sorry, I am still a beginner in java and android programming) – Alexandre Khoury Sep 24 '13 at 17:35
  • @Mageek No, my mistake.The idea was to set the minimum value when the text would be empty: `np.setValue(np.getMinValue());`. – user Sep 24 '13 at 17:37
  • But now, it becomes almost impossible to edit the number. Example: It's `7` and you want to put `2`. First, you erase with backspace and PAF it becomes `1`... – Alexandre Khoury Sep 24 '13 at 17:48
  • I had the idea to put `Integer.parseInt(s.toString())` in a temporary variable. And then use that var to get the value, but it crashes when I erase... – Alexandre Khoury Sep 24 '13 at 17:49
  • @Mageek I said to set the `NumberPicker` to the minim value so you don't end up with an empty `NumberPicker`. You can always use this in the `afterTextChanged()` method `if (s.toString.length() != 0) {np.setValue(Integer.parseInt(s.toString()));}`, just that I don't know how well will this go. – user Sep 24 '13 at 17:51
  • I'm telling that by doing that, at the moment you press backspace, it becomes `1`. (Instead of `""`) So you will never be able, for example, to set `5` because when you erase the previous value, it becomes 1, then you try to erase 1, and it stays. – Alexandre Khoury Sep 24 '13 at 17:53
  • @Mageek Unfortunately, I can't test right now what I've said but the code should work. I've edited my answer, for clarity, on how the code should look. I'll look into tomorrow with some testing. – user Sep 24 '13 at 18:06
  • Oh, I thought that I should ADD `if (s.toString.length() != 0) {np.setValue(Integer.parseInt(s.toString()));}` instead of replacing it. Now it's a lot better! But there is still a problem, it's if I put for example `4` as minimum and `20` as maximum, and the number is 17 and I want to put 13; I erase 7 and then it becomes 20 (because 1<4). – Alexandre Khoury Sep 24 '13 at 18:14
  • @Mageek I've seen that, As with the empty string you could impose another limit, so you'll be setting the `NumberPicker` value when it's at least equal minimum with the minimum value of `NumberPicker`. I've edited my answer again with this constraint. Keep in mind that with the new code, if you enter a value below the minimum constraint, the `NumberPicker` will not jump to the maximum value but also getting the value will point to the last value stored(like if you have 17 and delete 7, trying to get the value while 1 it's shown will still point to 17 as the `NumberPicker` wasn't updated yet). – user Sep 25 '13 at 07:06
2

I see that you already have an answer, however this may be useful to others. You can extend android.widget.NumberPicker and make your own where you can configure the EditText. As you type on the soft keyboard, the value of your NumberPicker is immediately set to the value you're typing.

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

In your XML-file you put the following:

<com.mypackage.MyNumberPicker
 android:id="@+id/numberPicker1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" />
Frank D.
  • 1,306
  • 1
  • 13
  • 23
1

You have to press the Done button for the value to programmatically change.

Razgriz
  • 7,179
  • 17
  • 78
  • 150
  • mine works now, so where you have the listener to press the positive button if you press clear focus it should work. There are two assumptions at this stage. Why it works is because the assumption is that you already inputed the text and when you call the clearFocus in the internal implementation of this method will get the value and set it on the internal number picker edittext – Alex Goja Apr 15 '16 at 09:26
1
NumberPicker np = (NumberPicker) findViewById(R.id.numberPicker1);
String[] nums = new String[20];
for(int i=0; i<nums.length; i++)
       nums[i] = Integer.toString(i);

np.setMinValue(1);
np.setMaxValue(20);
np.setWrapSelectorWheel(false);
np.setDisplayedValues(nums);
np.setValue(1);
Melih Altıntaş
  • 2,495
  • 1
  • 22
  • 35
  • I just found something really weird, see my edit. Do you know what to do? – Alexandre Khoury Sep 22 '13 at 15:14
  • This is weird android:theme="@android:style/Theme.Light.NoTitleBar" is related to statusbar If you want to remove the status bar,then use it – Melih Altıntaş Sep 22 '13 at 15:26
  • I decided to try this approach, having the same problem described in question. Unfortunately, this seems to have made no difference at all, the number picker still shows up exactly the same way and does exactly the same thing. I am not using the theme @Mageek mentions, very strange. Can anyone offer further insight on this? – Alan Moore Oct 17 '13 at 16:25
0

the reason why it doesn't work it's because if you look at the implementation of setValue in NumberPicker, it calls another method setValueInternal(int, boolean) which takes 2 parameters the new value and of course the bugger boolean which is representing whether it should notify the UI of any change or not. And guess what, in setValue the boolean goes always with false. Godammit. But there is one more trick I see that the validateInputTextView actually does it correctly, and it invokes when the edit text has no focus. maybe at the right time clearing the focus will do what is supposed to do.

Alex Goja
  • 548
  • 5
  • 18