0

I am trying to create a BaseAdapter which each element has a NumberPicker and a Button. The button's action parameters depends on the value picked in NumberPicker. One solution I thought was creating a setOnClickListener (of the button) inside the onValueChange of the NumberPicker, the problem is onValueChange never gets fired when I change the number.

I leave you the code to make it clearer:

public class Adapter extends BaseAdapter{
...

  public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null)
        {
            LayoutInflater vi = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.row, null);
        }
        button = (Button) v.findViewById(R.id.button);
        numPick = (NumberPicker) v.findViewById(R.id.numPick);
        numPick.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                val = newVal;
                button.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View arg0) {
                        actionToPerform(val);
                    }
                });
            }
        });

How can I solve this problem? Thank you!

Albert
  • 142
  • 1
  • 8

1 Answers1

0

Since the adapter will reuse the layout, you will need to set your listener when you create the layout. Move the button listener out. Otherwise, it will get set on every value change. Here is the revised code:

// Put the array as a member of your activity or fragment's class
// Remember to save it between life cycle event
// Initialize it to same size as your adapter data
int[] numValues;

public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null)
    {
        LayoutInflater vi = (LayoutInflater) con.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.row, null);

        final Button button = (Button) v.findViewById(R.id.button);
        final NumberPicker numPick = (NumberPicker) v.findViewById(R.id.numPick);

        button.setOnClickListener(new View.OnClickListener() {
                public void onClick(View arg0) {
                    // Get the position value from the tag field
                    int pos = (int)button.tag;
                    actionToPerform(numValues[pos]);
                }
            });

        numPick.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
        public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
              // Save the value in the number picker
              numPick.tag = newVal;
          }
        });
    }

    // Save the position in the button's tag field
    button.tag = position;
    // Restore picker value
    final NumberPicker numPick1 = (NumberPicker) v.findViewById(R.id.numPick);
    numPicker1.setValue(numValues[position]);

}

Saving the data in the tag field will ensure you get the right row's data when the button is clicked. I don't know how your data is represented so I introduce a int array to store the values. Otherwise, the picker will lose the value when it gets reused.

hfann
  • 599
  • 3
  • 13
  • First of all thank you for your answer. I do not understand several things. First of all what is tag? Can I use position from getView instead of button.tag (which I don't know how to extract a position from this last one). If theNumberPicker is a final variable then I can't access outside the if case. Thanks again! – Albert Jun 13 '14 at 22:49
  • The tag field is a View object field which is not used by Android. You can use it to store anything. The position variable in getView() contains the position information requested by the control to display stuff. When the user interact with the control on a row, the getView() doesn't get called. Therefore, I store the position in the tag field. This ensures the control on each row displayed knows its position. Sorry, I should define another var outside the if block. I have updated the code. – hfann Jun 14 '14 at 16:14
  • Now that I have asked that question, I have a similar problem. What if I have to change a text everytime I change a value in Number Picker? I can't update the text since I don't have a listener (like it does a button). Do you know how to do it? Thank you! – Albert Jun 15 '14 at 01:35
  • In the onValueChange() method of the number picker listener, you can call notifyDataSetChanged() method to force a redraw of the control. Then, display the current value numValues[positon] in the TextView. Place the setText() call right after you set the value of the NumberPicker after the if block. – hfann Jun 15 '14 at 19:51