@@ -94,11 +94,9 @@ export class DateTimePicker extends DateTimePickerBase {
9494 const alertTitle = options . title ? options . title : '' ;
9595 const alertController = UIAlertController . alertControllerWithTitleMessagePreferredStyle ( alertTitle , DateTimePicker . PICKER_DEFAULT_MESSAGE , UIAlertControllerStyle . ActionSheet ) ;
9696
97- let pickerContainerFrameTop = options . title ? DateTimePicker . PICKER_DEFAULT_TITLE_OFFSET : DateTimePicker . PICKER_DEFAULT_OFFSET ;
98- if ( options . title ) {
99- pickerContainerFrameTop += DateTimePicker . PICKER_DEFAULT_TITLE_HEIGHT ;
100- }
101- const pickerViewHeight = DateTimePicker . PICKER_DEFAULT_MESSAGE_HEIGHT ;
97+ const intrinsicPickerHeight = nativePicker . intrinsicContentSize . height ;
98+ const pickerViewHeight = intrinsicPickerHeight > 0 ? intrinsicPickerHeight : DateTimePicker . PICKER_DEFAULT_MESSAGE_HEIGHT ;
99+
102100 const pickerContainer = UIView . alloc ( ) . init ( ) ;
103101 pickerContainer . clipsToBounds = false ;
104102 let spinnersBackgroundColor = new Color ( 'transparent' ) ;
@@ -116,15 +114,16 @@ export class DateTimePicker extends DateTimePickerBase {
116114
117115 const messageLabel = DateTimePicker . _findLabelWithText ( alertController . view , DateTimePicker . PICKER_DEFAULT_MESSAGE ) ;
118116 const messageLabelContainer = DateTimePicker . _getLabelContainer ( messageLabel ) ;
117+ messageLabel . heightAnchor . constraintEqualToConstant ( pickerViewHeight ) . active = true ;
119118 // Disable clipping on all ancestor views to prevent wheel picker from being cut off
120119 DateTimePicker . _disableClipsToBoundsOnAncestors ( messageLabelContainer ) ;
121120 messageLabelContainer . addSubview ( pickerContainer ) ;
122121
123122 pickerContainer . translatesAutoresizingMaskIntoConstraints = false ;
124- pickerContainer . topAnchor . constraintEqualToAnchorConstant ( alertController . view . topAnchor , pickerContainerFrameTop ) . active = true ;
123+ pickerContainer . topAnchor . constraintEqualToAnchor ( options . title ? messageLabel . topAnchor : messageLabelContainer . topAnchor ) . active = true ;
125124 pickerContainer . leftAnchor . constraintEqualToAnchor ( alertController . view . leftAnchor ) . active = true ;
126125 pickerContainer . rightAnchor . constraintEqualToAnchor ( alertController . view . rightAnchor ) . active = true ;
127- pickerContainer . bottomAnchor . constraintEqualToAnchor ( alertController . view . bottomAnchor ) . active = true ;
126+ pickerContainer . heightAnchor . constraintEqualToConstant ( pickerViewHeight ) . active = true ;
128127
129128 // Use auto layout for the picker - constrain to container edges to prevent clipping
130129 pickerView . translatesAutoresizingMaskIntoConstraints = false ;
@@ -167,10 +166,29 @@ export class DateTimePicker extends DateTimePickerBase {
167166 }
168167
169168 if ( viewController ) {
169+ const iosVersion = parseFloat ( Device . osVersion ) ;
170+ const usesDefaultPhonePlacement = iosVersion >= 26 && ! DateTimePicker . _isTablet && ( ! options || options . iosPermittedArrowDirections === undefined ) ;
171+ const needsTitleOffset = usesDefaultPhonePlacement && iosVersion < 27 && ! ! options . title ;
172+ const positionAboveBottom = ( height : number ) => {
173+ const view = viewController . view ;
174+ const bottom = view . bounds . origin . y + view . bounds . size . height - view . safeAreaInsets . bottom - DateTimePicker . PICKER_DEFAULT_OFFSET ;
175+ const top = view . bounds . origin . y + view . safeAreaInsets . top ;
176+ nativeDialog . popoverPresentationController . sourceRect = CGRectMake ( view . bounds . origin . x + view . bounds . size . width / 2.0 , Math . max ( top , bottom - height - 1 ) , 1.0 , 1.0 ) ;
177+ } ;
170178 if ( nativeDialog . popoverPresentationController ) {
179+ const defaultArrowDirections = usesDefaultPhonePlacement ? UIPopoverArrowDirection . Up : UIPopoverArrowDirection . Any ;
180+ const sourceRectY = viewController . view . bounds . size . height / 2.0 ;
171181 nativeDialog . popoverPresentationController . sourceView = viewController . view ;
172- nativeDialog . popoverPresentationController . sourceRect = CGRectMake ( viewController . view . bounds . size . width / 2.0 , viewController . view . bounds . size . height / 2.0 , 1.0 , 1.0 ) ;
173- nativeDialog . popoverPresentationController . permittedArrowDirections = options && options . iosPermittedArrowDirections !== undefined ? options . iosPermittedArrowDirections : UIPopoverArrowDirection . Any ;
182+ nativeDialog . popoverPresentationController . sourceRect = CGRectMake ( viewController . view . bounds . size . width / 2.0 , sourceRectY , 1.0 , 1.0 ) ;
183+ nativeDialog . popoverPresentationController . permittedArrowDirections = options && options . iosPermittedArrowDirections !== undefined ? options . iosPermittedArrowDirections : defaultArrowDirections ;
184+ nativeDialog . popoverPresentationController . canOverlapSourceViewRect = true ;
185+ if ( usesDefaultPhonePlacement ) {
186+ // UIKit positions the popover from this estimate before presentation.
187+ const size = nativeDialog . view . systemLayoutSizeFittingSize ( CGSizeMake ( viewController . view . bounds . size . width , 0 ) ) ;
188+ const titleLabel = needsTitleOffset ? DateTimePicker . _findLabelWithText ( nativeDialog . view , options . title ) : null ;
189+ const titleHeight = titleLabel && titleLabel . intrinsicContentSize . height > 0 ? titleLabel . intrinsicContentSize . height : 0 ;
190+ positionAboveBottom ( Math . max ( 0 , size . height - titleHeight ) ) ;
191+ }
174192 }
175193
176194 viewController . presentViewControllerAnimatedCompletion ( nativeDialog , true , ( ) => { } ) ;
0 commit comments