react-native-timer-picker

repository·main·Indexed 42 days ago

https://github.com/troberts-28/react-native-timer-picker

A flexible and performant duration picker component for React Native apps, suitable for timers, alarms, and duration inputs. Version 2.7.0 supports Expo and bare React Native environments (>= 0.72.0), featuring iOS-style haptic and audio feedback, infinite scrolling, and a pre-built TimerPickerModal for full-screen selection. It offers deep customization for themes, 12-hour formats, and integration with linear gradients and masked views for advanced visual effects.

Tokens
13.8K
Snippets
23
Records
44
Agent score
52%

What's inside react-native-timer-picker

  1. Optimize Infinite Scroll Performance

    main

    The TimerPicker uses an auto-scrolling mechanism to simulate infinite scrolling. If you notice a momentary flicker when scrolling slowly, you can manage this using the following strategies:

    1. Adjust Repetitions: The picker repeats numbers a certain number of times to maintain the illusion. You can manually increase these values to reduce the frequency of auto-scrolling:

      • repeatHourNumbersNTimes
      • repeatMinuteNumbersNTimes
      • repeatSecondNumbersNTimes
    2. Disable Infinite Scroll: To completely avoid flickering, set the disableInfiniteScroll prop to true. If you do this, it is recommended to set the repetition props above to high values so users have to scroll significantly to reach the actual start or end of the list.

  2. Use a Custom FlatList component

    main

    To improve integration with libraries like react-native-gesture-handler (e.g., when using a Bottom Sheet), you can provide a custom FlatList component via the FlatList prop.

    Requirements: The custom component must implement the same interface as React Native's <FlatList />.

    Example: Integrating with react-native-gesture-handler If using a bottom sheet that interferes with scrolling detection, pass the FlatList from react-native-gesture-handler to the TimerPicker.

    import { FlatList } from 'react-native-gesture-handler';
    import { TimerPicker } from "react-native-timer-picker";
    
    // ...
    
    <TimerPicker
        {...props}
        FlatList={FlatList}
    />
  3. Implement picker feedback using the pickerFeedback prop

    main

    To provide audio or haptic feedback when the picker ticks onto a new number, use the pickerFeedback callback prop. This is the recommended approach and replaces the deprecated Expo-specific audio/haptic props.

    Implementation Example

    import { useCallback, useRef, useEffect } from "react";
    import { TimerPicker } from "react-native-timer-picker";
    import { AudioContext, type AudioBuffer } from "react-native-audio-api";
    import * as Haptics from 'expo-haptics';
    import { trigger } from 'react-native-haptic-feedback';
    
    // ... setup audio context and buffer in useEffect ...
    
    const pickerFeedback = useCallback(() => {
        try {
            // Audio implementation
            const context = audioContextRef.current;
            const buffer = audioBufferRef.current;
            if (context && buffer) {
                const playerNode = context.createBufferSource();
                playerNode.buffer = buffer;
                playerNode.connect(context.destination);
                playerNode.start(context.currentTime);
            }
    
            // Haptics implementation
            // For Expo:
            Haptics.selectionAsync();
            // For Bare RN:
            trigger('selection');
        } catch (e) {
            console.warn("Picker feedback failed", e);
        }
    }, [audioContextRef, audioBufferRef]);
    
    <TimerPicker
        {...props}
        pickerFeedback={pickerFeedback}
    />
  4. Configure 12-hour format and AM/PM picker

    main

    To switch the picker to a 12-hour format, use the use12HourPicker option. You can further customize how AM/PM is displayed using separateAmPmPicker.

    • use12HourPicker: Enables 12-hour format with AM/PM labels (default: false).
    • separateAmPmPicker: When use12HourPicker is true, renders AM/PM as a dedicated scrollable column after the seconds column. Note that onDurationChange still emits hours as a 0–23 value. (default: false).
    • amLabel: Custom string for the AM label (default: am).
    • pmLabel: Custom string for the PM label (default: pm).
  5. Configure Masked View for transparent fade-out

    main

    If you need the numbers to fade in/out on a transparent background (e.g., when the picker is over an image or a gradient), you must use @react-native-masked-view/masked-view in addition to a Linear Gradient component.

    Steps to implement:

    1. Install @react-native-masked-view/masked-view.
    2. Set backgroundColor: 'transparent' in the TimerPicker styles prop.
    3. Supply both the MaskedView component AND a Linear Gradient component as props to TimerPicker or TimerPickerModal.
  6. Configure infinite scroll and repetition settings

    main

    The picker uses repetition to simulate infinite scrolling. You can control how many times the number lists repeat and whether to disable the infinite scroll feature entirely.

    • repeatDayNumbersNTimes: Number of times the day list repeats (default: 3).
    • repeatHourNumbersNTimes: Number of times the hour list repeats (default: 7).
    • repeatMinuteNumbersNTimes: Number of times the minute list repeats (default: 3).
    • repeatSecondNumbersNTimes: Number of times the second list repeats (default: 3).
    • disableInfiniteScroll: Disables the infinite scroll feature (default: false).
  7. Configure Custom Styles for TimerPicker

    main

    You can customize the appearance of the TimerPicker using several style props.

    Basic Theme Props

    Use these props for high-level adjustments:

    • theme: Set to "light" or "dark".
    • backgroundColor: Sets the main background color.
    • text: Applies a base TextStyle to all text.
    • pickerLabelGap: Sets the pixel gap between the label and the picker number column. Accepts a PerColumnValue.
    • pickerColumnWidth: Sets the width of individual picker columns. Overrides default flex-based sizing. Accepts a PerColumnValue.

    PerColumnValue type: number | { days?: number, hours?: number, minutes?: number, seconds?: number }. You can pass a single number for all columns or an object to specify values per column.

    Note: labelOffsetPercentage is deprecated. Use pickerLabelGap instead.

    Deep Style Customization

    For granular control, you can provide custom styles for internal components. These are applied on top of default styles. Common style props include:

    • pickerContainer: Main container (ViewStyle & { backgroundColor?: string }).
    • pickerLabelContainer: Container for labels (ViewStyle).
    • pickerLabel: Style for labels (TextStyle).
    • pickerItemContainer: Container for each number (ViewStyle & { height?: number }).
    • pickerItem: Style for each number (TextStyle).
    • selectedPickerItem: Style for the currently selected number (TextStyle).
    • disabledPickerItem: Style for numbers outside set limits (TextStyle).
    • durationScrollFlatList: Style for the FlatList in each picker (ViewStyle).

    Limitations: pickerContainer.backgroundColor and pickerItemContainer.height must be simple values (string and number respectively) to avoid breaking internal scroll positioning and snap behavior.

  8. Configure Linear Gradient for fade-in/out effects

    main

    To enable the effect where numbers fade in/out at the top and bottom of the picker, you must install and provide a linear gradient component as a prop to TimerPicker or TimerPickerModal.

    • For Expo projects: Install expo-linear-gradient.
    • For bare React Native projects: Install react-native-linear-gradient.

    You must supply the installed component as a prop to the picker component to activate the effect.

  9. Configure picker labels and zero padding

    main

    You can customize the labels displayed for each time unit and control whether single-digit values are padded with a leading zero.

    Labels:

    • dayLabel: Label for days (default: d)
    • hourLabel: Label for hours (default: h)
    • minuteLabel: Label for minutes (default: m)
    • secondLabel: Label for seconds (default: s)

    Zero Padding:

    • padDaysWithZero: Pad single-digit days (default: false)
    • padHoursWithZero: Pad single-digit hours (default: false)
    • padMinutesWithZero: Pad single-digit minutes (default: true)
    • padSecondsWithZero: Pad single-digit seconds (default: true)
  10. Avoid deprecated Expo-specific feedback props

    main

    As of v2.2.0, the following props are deprecated and should no longer be used:

    • Passing the Haptics namespace (from expo-haptics) as a prop.
    • Passing the Audio class (from expo-av) as a prop.

    Why? expo-av has high latency, which causes audio to lag behind rapid scrolling. Use the pickerFeedback callback prop instead to implement low-latency feedback using libraries like react-native-audio-api or expo-haptics.

  11. Customize TimerPickerModal buttons

    main

    You can replace the default 'Cancel' and 'Confirm' buttons in TimerPickerModal with your own custom React components using the cancelButton and confirmButton props.

    import { TimerPickerModal } from "react-native-timer-picker";
    import { TouchableOpacity, Text } from "react-native";
    
    const CustomButton = ({ label, onPress }) => (
        <TouchableOpacity onPress={onPress}>
            <Text>{label}</Text>
        </TouchableOpacity>
    );
    
    // ...
    <TimerPickerModal
        cancelButton={<CustomButton label="Cancel" />}
        confirmButton={<CustomButton label="Confirm" />}
        // ... other props
    />