0

I want to create a NumberPicker with an array of displayed values. The values are not supposed to change when the NumberPicker is displayed, but the min and max values change dynamically depending on user action.

Here is the code:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <NumberPicker
        android:id="@+id/picker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>
</RelativeLayout>

In Main Activity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final String[] values = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

        NumberPicker picker = (NumberPicker) findViewById(R.id.picker);
        picker.setDisplayedValues(values);
        picker.setMaxValue(7);
        picker.setMinValue(3);

        picker.setWrapSelectorWheel(false);
    }
}

When I set the maximum without setting the minimum, I end with displayed values between "0" and "7" (included). If I set the minValue to 0 I have the same behaviour. But if I set the minValue to 3 I end with displayed values between "0" and "4". When it's supposed to be between "3" and "7".

I don't understand why. Have I done something wrong or is there an issue with the component?

Ankita Shah
  • 1,866
  • 16
  • 31
Eselfar
  • 3,759
  • 3
  • 23
  • 43

3 Answers3

3

If you look at the implementation of setMinValue or setMaxValue there is a comment that says:

 * <strong>Note:</strong> The length of the displayed values array
 * set via {@link #setDisplayedValues(String[])} must be equal to the
 * range of selectable numbers which is equal to
 * {@link #getMaxValue()} - {@link #getMinValue()} + 1.

So to work around this it is best to just set the value list when you want to update the displayed values.

//do this once in onCreate and save the values list somewhere where you have access
final List<String> values = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
    values.add(String.valueOf(i));
}
NumberPicker picker = (NumberPicker) findViewById(R.id.picker);
picker.setWrapSelectorWheel(false);


//do this every time you want to change the displayed values and set minValue and maxValue accordingly
//also make sure that you stay within the bounds of value
int minValue = 3;
int maxValue = 7;

final List<String> subValues = values.subList(minValue, maxValue + 1);
String[] subValuesArray = new String[subValues.size()];
subValuesArray = subValues.toArray(subValuesArray);
picker.setDisplayedValues(subValuesArray);
picker.setMinValue(0);
picker.setMaxValue(subValues.size() - 1);
Bmuig
  • 1,059
  • 7
  • 12
  • Could you please elaborate on this? Why does it not fix the OP's issue? Didn't you also propose that the display value should be changed whenever the min / max value changes (maybe I misunderstood that)? – Bmuig Feb 23 '17 at 16:19
  • My apologies, I misread your suggestion. It works as expected. Sorry for that! – Eugen Martynov Feb 23 '17 at 17:01
2

for brevity to @Bmuig answer, just a helper function:

private void configurePicker(NumberPicker picker, ArrayList<String> values, int minValue, int maxValue, int currentValue) {
    picker.setDisplayedValues(values) //to avoid out of bounds
    picker.setMinValue(minValue);
    picker.setMaxValue(maxValue);
    picker.setValue(currentValue);
    picker.setDisplayedValues((String[]) values.subList(minValue, maxValue + 1).toArray());
}
Joe Maher
  • 5,354
  • 5
  • 28
  • 44
1

It is explainable from the documentation.

When you set min and max, you define int values that can be entered with NumberPicker. So setValue(int) only accepts values from min to max.

The displayValues() is labels override. And it will be used in a next manner - NumberPicker will take label with index value - min.

Eugen Martynov
  • 19,888
  • 10
  • 61
  • 114