2

Can't believe I haven't found an answered Stack Overflow post about this...

I'm making a timer where you select the time from a NumberPicker widget. The problem is that it takes 10-13 scrolls to get to the bottom

I looked in the documentation but haven't found anything

String[] minsecvalues = new String[61];

for(int i=0; i < minsecvalues.length; i++){
        minsecvalues[i] = Integer.toString(i);
}

NumberPicker mSecondsPicker = (NumberPicker) v.findViewById(R.id.np_seconds_picker);
mSecondsPicker.setMaxValue(60);
mSecondsPicker.setMinValue(0);
mSecondsPicker.setWrapSelectorWheel(true);
mSecondsPicker.setDisplayedValues(minsecvalues);

//supposed to change scroll speed but doesn't work
mSecondsPicker.setOnLongPressUpdateInterval(8000);
//This method looks promising but my app crashes when I run it
//mSecondsPicker.scrollBy(0, 20);
Raj
  • 2,997
  • 2
  • 12
  • 30
Claudiu Moise
  • 376
  • 3
  • 14

4 Answers4

1

There is no public way to access friction level in the default NumberPicker widget.

You can use this custom NumberPickerView. Installation instructions in english are here.

It does exactly what you want with the method below to control friction level:

//double the default scroll friction level
mNumberPickerView.setFriction(2 * ViewConfiguration.get(mContext).getScrollFriction());

The default scroll friction value is 0.015f and can be found here

MatPag
  • 41,742
  • 14
  • 105
  • 114
  • Great library, but the drawback is that it lacks the EditText functionality, i.e. typing to choose the desired value. – Max Feb 26 '23 at 15:13
1

I have seen a few questions relating to this point (such as here and here).

The variable in NumberPicker associated with maximum scroll speed is set to private by default. Fortunately, we can use reflection to access and change these values. Why the class doesn't have a public method for altering something as basic as scroll speed is beyond me.

Digging around in the source code for NumberPicker here I found this to be the private int mMaximumFlingVelocity variable.

Assuming numberPicker is our NumberPicker:

// Can set this value to anything to modify our scroll speed, where a value
// between 0 and 1 makes the scroll speed slower, and anything greater than
// 1 makes it faster (e.g. a factor of 2 makes it twice as fast)
final double scrollSpeedFactor = 2;

// Surrounding by try/catch is required here because Class.getDeclaredField
// can throw a NoSuchFieldException and Field.get can throw an IllegalAccessException
try {
    // Our private field is accessed with getDeclaredField
    Field field = numberPicker.getClass().getDeclaredField("mMaximumFlingVelocity");

    // We make the field accessible
    field.setAccessible(true);

    // Get the value
    int maxVelocityValue = (int) field.get(numberPicker);

    // Set a new velocity value based on our scrollSpeedFactor
    int newVelocityValue = (int) (maxVelocityValue * scrollSpeedFactor);

    // Set the new velocity
    field.setInt(numberPicker, newVelocityValue);
} 
catch (NoSuchFieldException | IllegalAccessException e) {
    e.printStackTrace();
}
Dantic
  • 11
  • 2
  • Starting with API level 31, the field `mMaximumFlingVelocity` is a blacklisted non-SDK API (https://developer.android.com/about/versions/12/non-sdk-12#new-blocked lists `Landroid/widget/NumberPicker;->mMaximumFlingVelocity:I`), meaning that it cannot be normally accessed via reflection (`NoSuchFieldException` will be thrown, as described in https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces#results-of-keeping-non-sdk). However, there are ways to work around that restriction, such as described in https://stackoverflow.com/a/55970138/11105280). – Max Feb 26 '23 at 15:11
0

My ScrollPicker library could be of help here but unfortunately it can't have the 'selector wheel' 'wrapped', so no looped display of the list is available.
While you can't set the scrolling speed from code, you don't have to, because you can get to the end of those 60 items in 1 swipe. This is the reason why I think it still might be suitable for you. You can control your swipe speed by the velocity you do on your swipes.

Here's what you have to do:
1. Use ScrollPicker instead of NumberPicker
2. Set your Collection in code with setItems(..). No setMinValue, setMaxValue or conversion to Strings is necessary, just set your int Collection.

0

I haven't been able to find a solution for this either but I just wanted to clarify on why

mSecondsPicker.setOnLongPressUpdateInterval(8000);

isn't working the way you are expecting it to. The description for this method is "Sets the speed at which the numbers be incremented and decremented when the up and down buttons are long pressed respectively." Meaning that rather than controlling swipe speed it only affects the scroll speed when you hold the up and down buttons. I believe the "up and down" buttons for the default NumberPicker are the numbers above and below the highlighted or selected number in the NumberPicker.

Kevin Barron
  • 88
  • 2
  • 9