Skip to content

Commit e96f061

Browse files
authored
feat: support preferredDatePickerStyle in iOS 14 (#246)
BREAKING CHANGE: you need XCode 11 to build this version, and you need this version to properly support iOS 14 (for that you need XCode 12) This adds support for preferredDatePickerStyle to the module. We took the android-only display prop and extended the support for iOS too, as opposed to adding a new ios-only prop.
1 parent d50bb5c commit e96f061

18 files changed

+683
-474
lines changed

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ React Native date & time picker component for iOS, Android and Windows.
4040
- [Basic usage with state](#basic-usage-with-state)
4141
- [Props](#props)
4242
- [`mode` (`optional`)](#mode-optional)
43-
- [`display` (`optional`, `Android only`)](#display-optional-android-only)
43+
- [`display` (`optional`)](#display-optional)
4444
- [`onChange` (`optional`)](#onchange-optional)
4545
- [`value` (`required`)](#value-required)
4646
- [`maximumDate` (`optional`)](#maximumdate-optional)
@@ -69,7 +69,7 @@ React Native date & time picker component for iOS, Android and Windows.
6969

7070
## Requirements
7171

72-
- Xcode >= 10
72+
- Xcode >= 11
7373

7474
## Expo users notice
7575

@@ -192,17 +192,24 @@ List of possible values:
192192
<RNDateTimePicker mode="time" />
193193
```
194194

195-
#### `display` (`optional`, `Android only`)
195+
#### `display` (`optional`)
196196

197-
Defines the visual display of the picker for Android and will be ignored for iOS.
197+
Defines the visual display of the picker. The default value is `"default"`.
198198

199-
List of possible values:
199+
List of possible values for Android
200200

201-
- `"default"` - Show a default date picker (spinner/calendar/clock) based on `mode` and android version.
201+
- `"default"` - Show a default date picker (spinner/calendar/clock) based on `mode` and Android version.
202202
- `"spinner"`
203203
- `"calendar"` (only for `date` mode)
204204
- `"clock"` (only for `time` mode)
205205

206+
List of possible values for iOS (maps to [preferredDatePickerStyle](https://developer.apple.com/documentation/uikit/uidatepicker/3526124-preferreddatepickerstyle?changes=latest_minor&language=objc))
207+
208+
- `"default"` - Automatically pick the best style available for the current platform & mode.
209+
- `"spinner"` - the usual appearance with a wheel from which you choose values
210+
- `"compact"` - Affects only iOS 14 and later. Will fall back to "spinner" if not supported.
211+
- `"inline"` - Affects only iOS 14 and later. Will fall back to "spinner" if not supported.
212+
206213
```js
207214
<RNDateTimePicker display="spinner" />
208215
```

example/App.js

Lines changed: 61 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,18 @@ import {
1111
useColorScheme,
1212
} from 'react-native';
1313
import DateTimePicker from '@react-native-community/datetimepicker';
14+
import SegmentedControl from '@react-native-community/segmented-control';
1415
import {Colors} from 'react-native/Libraries/NewAppScreen';
1516
import React, {useState} from 'react';
1617
import {Picker} from 'react-native-windows';
1718
import moment from 'moment';
18-
import {DAY_OF_WEEK} from '../src/constants';
19+
import {
20+
ANDROID_MODE,
21+
DAY_OF_WEEK,
22+
IOS_MODE,
23+
ANDROID_DISPLAY,
24+
IOS_DISPLAY,
25+
} from '../src/constants';
1926

2027
const ThemedText = (props) => {
2128
const isDarkMode = useColorScheme() === 'dark';
@@ -28,19 +35,28 @@ const ThemedText = (props) => {
2835
});
2936
};
3037

38+
const MODE_VALUES = Platform.select({
39+
ios: Object.values(IOS_MODE),
40+
android: Object.values(ANDROID_MODE),
41+
});
42+
const DISPLAY_VALUES = Platform.select({
43+
ios: Object.values(IOS_DISPLAY),
44+
android: Object.values(ANDROID_DISPLAY),
45+
});
46+
const MINUTE_INTERVALS = [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30];
47+
3148
export const App = () => {
3249
const [date, setDate] = useState(new Date(1598051730000));
33-
const [time, setTime] = useState(undefined);
34-
const [mode, setMode] = useState('date');
50+
const [mode, setMode] = useState(MODE_VALUES[0]);
3551
const [show, setShow] = useState(false);
3652
const [color, setColor] = useState();
37-
const [display, setDisplay] = useState('default');
38-
const [interval, setMinInterval] = useState(undefined);
39-
const [minuteInterval, setMinuteInterval] = useState(1);
53+
const [display, setDisplay] = useState(DISPLAY_VALUES[0]);
54+
const [interval, setMinInterval] = useState(1);
4055

4156
// Windows-specific
42-
const maxDate = useState(new Date('2021'));
43-
const minDate = useState(new Date('2018'));
57+
const [time, setTime] = useState(undefined);
58+
const [maxDate, setMinDate] = useState(new Date('2021'));
59+
const [minDate, setMaxDate] = useState(new Date('2018'));
4460
const [is24Hours, set24Hours] = useState(false);
4561
const [firstDayOfWeek, setFirstDayOfWeek] = useState(DAY_OF_WEEK.Monday);
4662
const [dateFormat, setDateFormat] = useState('longdate');
@@ -65,43 +81,6 @@ export const App = () => {
6581
}
6682
};
6783

68-
const showMode = (currentMode) => {
69-
setShow(true);
70-
setMode(currentMode);
71-
};
72-
73-
const showDatepicker = () => {
74-
showMode('date');
75-
setDisplay('default');
76-
};
77-
78-
const showDatepickerSpinner = () => {
79-
showMode('date');
80-
setDisplay('spinner');
81-
};
82-
83-
const showTimepicker = () => {
84-
showMode('time');
85-
setDisplay('default');
86-
};
87-
88-
const showTimepickerSpinner = () => {
89-
showMode('time');
90-
setDisplay('spinner');
91-
};
92-
93-
const showTimepickerClockModeWithInterval = () => {
94-
showMode('time');
95-
setMinInterval(5);
96-
setDisplay('clock');
97-
};
98-
99-
const showTimepickerSpinnerWithInterval = () => {
100-
showMode('time');
101-
setMinInterval(5);
102-
setDisplay('spinner');
103-
};
104-
10584
const isDarkMode = useColorScheme() === 'dark';
10685

10786
const backgroundStyle = {
@@ -130,6 +109,34 @@ export const App = () => {
130109
Example DateTime Picker
131110
</ThemedText>
132111
</View>
112+
<ThemedText>mode prop:</ThemedText>
113+
<SegmentedControl
114+
values={MODE_VALUES}
115+
selectedIndex={MODE_VALUES.indexOf(mode)}
116+
onChange={(event) => {
117+
setMode(MODE_VALUES[event.nativeEvent.selectedSegmentIndex]);
118+
}}
119+
/>
120+
<ThemedText>display prop:</ThemedText>
121+
<SegmentedControl
122+
values={DISPLAY_VALUES}
123+
selectedIndex={DISPLAY_VALUES.indexOf(display)}
124+
onChange={(event) => {
125+
setDisplay(
126+
DISPLAY_VALUES[event.nativeEvent.selectedSegmentIndex],
127+
);
128+
}}
129+
/>
130+
<ThemedText>minute interval prop:</ThemedText>
131+
<SegmentedControl
132+
values={MINUTE_INTERVALS.map(String)}
133+
selectedIndex={MINUTE_INTERVALS.indexOf(interval)}
134+
onChange={(event) => {
135+
setMinInterval(
136+
MINUTE_INTERVALS[event.nativeEvent.selectedSegmentIndex],
137+
);
138+
}}
139+
/>
133140
<View style={styles.header}>
134141
<ThemedText style={{margin: 10, flex: 1}}>
135142
text color (iOS only)
@@ -145,46 +152,14 @@ export const App = () => {
145152
</View>
146153
<View style={styles.button}>
147154
<Button
148-
testID="datePickerButton"
149-
onPress={showDatepicker}
150-
title="Show date picker default!"
151-
/>
152-
</View>
153-
<View style={styles.button}>
154-
<Button
155-
testID="datePickerButtonSpinner"
156-
onPress={showDatepickerSpinner}
157-
title="Show date picker spinner!"
158-
/>
159-
</View>
160-
<View style={styles.button}>
161-
<Button
162-
testID="timePickerButton"
163-
onPress={showTimepicker}
164-
title="Show time picker!"
165-
/>
166-
</View>
167-
<View style={styles.button}>
168-
<Button
169-
testID="timePickerButtonSpinner"
170-
onPress={showTimepickerSpinner}
171-
title="Show time picker spinner!"
172-
/>
173-
</View>
174-
<View style={styles.button}>
175-
<Button
176-
testID="timePickerDefaultIntervalButton"
177-
onPress={showTimepickerClockModeWithInterval}
178-
title="Show time picker as clock (with 5 min interval)!"
179-
/>
180-
</View>
181-
<View style={styles.button}>
182-
<Button
183-
testID="timePickerSpinnerIntervalButton"
184-
onPress={showTimepickerSpinnerWithInterval}
185-
title="Show time picker as spinner (with 5 min interval)!"
155+
testID="showPickerButton"
156+
onPress={() => {
157+
setShow(true);
158+
}}
159+
title="Show picker!"
186160
/>
187161
</View>
162+
188163
<View style={styles.header}>
189164
<ThemedText testID="dateText" style={styles.dateTimeText}>
190165
{moment.utc(date).format('MM/DD/YYYY')}
@@ -336,8 +311,8 @@ export const App = () => {
336311
<Text style={{padding: 10}}>Minute interval: </Text>
337312
<Picker
338313
style={{width: 200, height: 35}}
339-
selectedValue={minuteInterval}
340-
onValueChange={(value) => setMinuteInterval(value)}>
314+
selectedValue={interval}
315+
onValueChange={(value) => setMinInterval(value)}>
341316
<Picker.Item label="1 minute step" value={1} />
342317
<Picker.Item label="12 minute step" value={12} />
343318
<Picker.Item label="15 minute step" value={15} />
@@ -350,7 +325,7 @@ export const App = () => {
350325
style={{width: 300, opacity: 1, height: 30, marginTop: 50}}
351326
onChange={onTimeChange}
352327
is24Hour={is24Hours}
353-
minuteInterval={minuteInterval}
328+
minuteInterval={interval}
354329
/>
355330
<View style={styles.header}>
356331
<Text style={styles.dateTimeText}>

0 commit comments

Comments
 (0)