androidandroid-number-picker

setMinValue on NumberPicker doesn't select the correct min value


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?


Solution

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