Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android picker does not scroll back to desired index #59

Open
samzmann opened this issue Apr 29, 2019 · 6 comments
Open

Android picker does not scroll back to desired index #59

samzmann opened this issue Apr 29, 2019 · 6 comments

Comments

@samzmann
Copy link

samzmann commented Apr 29, 2019

I'm making a basic time picker with two wheels: hour, minutes.
If the selected time is not valid, the wheel should turn back to the previously valid time.

For example, let's say it is 10:30am so valid times are 10:30am - 11:59pm. If the user selected 10:15, I expect the minute wheel to scroll back to 10:30.

This is working fine on iOS, but on Android, the wheel simply stays at the invalid index.

So my question is: how to enable programmatic scroll to an index of the picker on Android to achieve the same behavior as iOS?

Thanks :)

Env:
react-native 0.57.8
react-native-wheel-picker 1.2.0

@samzmann samzmann changed the title Android picker does not roll back to desired index Android picker does not scroll back to desired index programmatically Apr 29, 2019
@samzmann samzmann changed the title Android picker does not scroll back to desired index programmatically Android picker does not scroll back to desired index Apr 29, 2019
@samzmann
Copy link
Author

samzmann commented May 2, 2019

So basically I guess the problem is the picker does not rerender when the props used for selectedValue have not changed. This is really weird because I see that the underlying <WheelCurvedPicker> props for selectedValue do change.

@sebackend
Copy link

I have a similar problem but in iOS. In fact, i'm doing the same input (HH:MM) with 2 scrolls. My problem is after scroll and select any hour or minute, the input is scroll down automatically to the initial value at the bottom (the value is updated in my local state, but after select, there is another scroll that i cannot manage, it is done without any interaction).

Any idea?

@samzmann
Copy link
Author

@sebackend maybe you have some mistake in your onValueChange call, or how you call setState

Happy to help if u share code. However, I don't think this should be discussed in here as it sound like a somewhat different problem, plus its iOS and this issue thread is on Android only.

@riki-gertzik
Copy link

So basically I guess the problem is the picker does not rerender when the props used for selectedValue have not changed. This is really weird because I see that the underlying <WheelCurvedPicker> props for selectedValue do change.

Hey @Lavielle I have kind of that issue on an Android device (ios works fine). Did you manage to resolve your issue?

@samzmann
Copy link
Author

samzmann commented Mar 23, 2020

@riki-gertzik For us the solution was to only show valid data. So when the user mounts this picker wheel, we calculate valid times and generate an array to populate the picker. Then, when the user makes a selection, we check if the time is valid (slightly differently for iOS and Android).
This is the function we use to handle picker selection, wrote almost a year a go so I don't fully understand it anymore, but hopefully you can get something out of it.

Note: the quickSelector you'll see bellow is some other UI element that allows user to pick relative time (eg. "in 15 mins"), and is not related to the time picker wheel

/**
 *   selectedPicker: {
 *     hour: String // "00" - "23"
 *     minute: String // "00" - "59"
 *     value: Moment // the full time/date for that valid time
 *   }
*/

handleTimePickerChange = (selectedPicker) => {
    const { validPickupTimesForDay, lastQuickSelectorReset, quickSelector } = this.state
    let { selectedHour, selectedMinute, selectedTime } = this.state

    // assumes we should reset quickSelector because iOS functions as expected:
    // onValueChange fires only on manual change
    let resetQuickSelector = true

    // 'debounce' quickSelector reset on Android:
    // onValueChange fires when Picker values are changed programmatically (not expected)
    // this happens only on Android, so we check if the last quickSelector change was long ago and reset it only then
    if (Platform.OS === 'android') {
      const now = moment().subtract(1500, 'ms')
      resetQuickSelector = quickSelector !== null && now.isAfter(lastQuickSelectorReset)
    }
    const validTime = this.checkValidity(validPickupTimesForDay, selectedPicker)
    if (validTime) {
      if (selectedPicker.type === 'hour') {
        selectedHour = selectedPicker
        selectedTime = validTime
      }
      if (selectedPicker.type === 'minute') {
        selectedMinute = selectedPicker
        selectedTime = validTime
      }
    } else if (selectedPicker.type === 'hour' && selectedPicker.index === 0) {
      // hour:minute combination is not valid, so reset minutes to soonest valid minute
      selectedMinute = {
        label: validPickupTimesForDay[0].minute,
        index: validPickupTimesForDay[0].value.get('minutes'),
      }
      selectedTime = this.getValidTime(validPickupTimesForDay, selectedPicker.label, selectedMinute.label)
      selectedHour = selectedPicker
    }
    this.setState({
      selectedHour,
      selectedMinute,
      selectedTime,
      quickSelector: resetQuickSelector ? null : quickSelector,
    })
  }

@riki-gertzik
Copy link

@riki-gertzik For us the solution was to only show valid data. So when the user mounts this picker wheel, we calculate valid times and generate an array to populate the picker. Then, when the user makes a selection, we check if the time is valid (slightly differently for iOS and Android).
This is the function we use to handle picker selection, wrote almost a year a go so I don't fully understand it anymore, but hopefully you can get something out of it.

Note: the quickSelector you'll see bellow is some other UI element that allows user to pick relative time (eg. "in 15 mins"), and is not related to the time picker wheel

/**
 *   selectedPicker: {
 *     hour: String // "00" - "23"
 *     minute: String // "00" - "59"
 *     value: Moment // the full time/date for that valid time
 *   }
*/

handleTimePickerChange = (selectedPicker) => {
    const { validPickupTimesForDay, lastQuickSelectorReset, quickSelector } = this.state
    let { selectedHour, selectedMinute, selectedTime } = this.state

    // assumes we should reset quickSelector because iOS functions as expected:
    // onValueChange fires only on manual change
    let resetQuickSelector = true

    // 'debounce' quickSelector reset on Android:
    // onValueChange fires when Picker values are changed programmatically (not expected)
    // this happens only on Android, so we check if the last quickSelector change was long ago and reset it only then
    if (Platform.OS === 'android') {
      const now = moment().subtract(1500, 'ms')
      resetQuickSelector = quickSelector !== null && now.isAfter(lastQuickSelectorReset)
    }
    const validTime = this.checkValidity(validPickupTimesForDay, selectedPicker)
    if (validTime) {
      if (selectedPicker.type === 'hour') {
        selectedHour = selectedPicker
        selectedTime = validTime
      }
      if (selectedPicker.type === 'minute') {
        selectedMinute = selectedPicker
        selectedTime = validTime
      }
    } else if (selectedPicker.type === 'hour' && selectedPicker.index === 0) {
      // hour:minute combination is not valid, so reset minutes to soonest valid minute
      selectedMinute = {
        label: validPickupTimesForDay[0].minute,
        index: validPickupTimesForDay[0].value.get('minutes'),
      }
      selectedTime = this.getValidTime(validPickupTimesForDay, selectedPicker.label, selectedMinute.label)
      selectedHour = selectedPicker
    }
    this.setState({
      selectedHour,
      selectedMinute,
      selectedTime,
      quickSelector: resetQuickSelector ? null : quickSelector,
    })
  }

thanks @Lavielle for your response, our problem is that we have one wheel for degrees, where you can switch between C and F but if the new item "value" is the same as the old one ("value" = index), I don't see the new items but the old items until I do some change - press or start scrolling.
anyway, seems like a different problem.. I think it's related to when onValueChange called too but I'm not sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants