erksch / react-native-wheely

An all JavaScript wheel picker for react-native without any native code.
413 stars 59 forks source link

React-native-wheely infinite scroll #42

Open GiorgosKatsinoulas opened 1 year ago

GiorgosKatsinoulas commented 1 year ago

Hi, is it possible when I reach the last item on my list to show again the first item? Like infinite scroll at the picker wheely?

erksch commented 1 year ago

Cool idea, but I will not be able to implement it, you can give it a try and make PR :)

Mahmood-AlHajjo commented 1 month ago

@erksch you can make an infinite scroll like this:

const InfiniteWheelPicker = ({
  options,
  selectedIndex,
  onChange,
  ...rest
}) => {
  const extendedOptions = [...options, ...options, ...options];
  const middleIndex = Math.floor(extendedOptions.length / 3) + selectedIndex;
  const handleIndexChange = index => {
    const newIndex = index % options.length;
    onChange(newIndex);
  };

  return (
    <WheelPicker
      selectedIndex={middleIndex}
      options={extendedOptions}
      onChange={handleIndexChange}
      flatListProps={{
        initialNumToRender: extendedOptions.length,
        getItemLayout: (_, index) => ({ length: 45, offset: 45 * index, index }),
      }}
      visibleRest={4}
      itemHeight={45}
      {...rest}
    />
  );
};

and you can call it like this:

 const [selectedHour, setSelectedHour] = useState(12);
  const hours = Array.from({ length: 12 }, (_, i) => (i + 1).toString());

  <InfiniteWheelPicker
            selectedIndex={hours.indexOf(selectedHour.toString())}
            options={hours}
            onChange={index => setSelectedHour(hours[index])}
            itemStyle={styles.itemStyle}
            itemTextStyle={{
              fontSize: 18,
              fontWeight: 'bold',
            }}
            containerStyle={{ flex: 1, alignItems: 'flex-end' }}
            selectedIndicatorStyle={{
              backgroundColor: '#F4F4F5',
              borderRadius: 0,
              borderTopLeftRadius: 8,
              borderBottomLeftRadius: 8,
            }}
          />

https://github.com/user-attachments/assets/e66a412c-3324-4acb-a99b-02257f48e835

I hope that is helpful.

haerim95 commented 1 month ago

@Mahmood-AlHajjo

YOU GENIUS 🤩 Just what I needed

erksch commented 1 month ago

@Mahmood-AlHajjo Pretty cool trick 😄

haerim95 commented 1 month ago

@Mahmood-AlHajjo

I have a question about your trick. I only want to give visibleRest a value of 1, because I only want to show one value above and one below.

  const [selectedMinute, setSelectedMinute] = useState<number>(Number(minute));
  const hours = Array.from({ length: 60 }, (_, i) => (i + 1).toString());

  <InfiniteWheelPicker
            selectedIndex={hours.indexOf(selectedHour.toString())}
            options={hours}
            onChange={index => setSelectedHour(hours[index])}
            itemStyle={styles.itemStyle}
            itemTextStyle={{
              fontSize: 18,
              fontWeight: 'bold',
            }}
            containerStyle={{ flex: 1, alignItems: 'flex-end' }}
            selectedIndicatorStyle={{
              backgroundColor: '#F4F4F5',
              borderRadius: 0,
              borderTopLeftRadius: 8,
              borderBottomLeftRadius: 8,
            }}
          />
const InfiniteWheelPicker = ({
  options,
  selectedIndex,
  onChange,
  ...rest
}) => {
  const extendedOptions = [...options, ...options, ...options];
  const middleIndex = Math.floor(extendedOptions.length / 3) + selectedIndex;
  const handleIndexChange = index => {
    const newIndex = index % options.length;
    onChange(newIndex);
  };

  return (
    <WheelPicker
      selectedIndex={middleIndex}
      options={extendedOptions}
      onChange={handleIndexChange}
      flatListProps={{
        initialNumToRender: extendedOptions.length,
        getItemLayout: (_, index) => ({ length: 70, offset: 70 * index, index }),
      }}
      visibleRest={1}
      itemHeight={70}
      {...rest}
    />
  );
};

Aug-14-2024 14-40-31

But visibleRest={1} is not available. The option disappears like this, and then you scroll back to see it again.. If I give visibleRest a value of 4, this doesn't happen, but I only want to show three.

Is there any solution to this problem? This issue only occurs when implementing minutes.