@@ -22,13 +22,15 @@ @interface TrueSheetViewController ()
2222
2323@implementation TrueSheetViewController {
2424 CGFloat _lastPosition;
25- BOOL _isDragging;
2625 NSInteger _pendingDetentIndex;
26+ BOOL _pendingContentSizeChange;
2727
28- // Transitioning tracker
28+ // Position tracking
2929 CADisplayLink *_transitioningTimer;
3030 UIView *_transitionFakeView;
31+ BOOL _isDragging;
3132 BOOL _isTransitioning;
33+ BOOL _isTrackingPositionFromLayout;
3234
3335 // Reference to parent TrueSheetViewController (if presented from another sheet)
3436 __weak TrueSheetViewController *_parentSheetController;
@@ -61,10 +63,13 @@ - (instancetype)init {
6163 _lastPosition = 0 ;
6264 _isDragging = NO ;
6365 _isPresented = NO ;
66+ _pendingContentSizeChange = NO ;
6467 _activeDetentIndex = -1 ;
6568 _pendingDetentIndex = -1 ;
69+
6670 _isTransitioning = NO ;
6771 _transitionFakeView = [UIView new ];
72+ _isTrackingPositionFromLayout = NO ;
6873
6974 _blurInteraction = YES ;
7075 _resolvedDetentPositions = [NSMutableArray array ];
@@ -200,6 +205,9 @@ - (void)viewDidAppear:(BOOL)animated {
200205 if ([self .delegate respondsToSelector: @selector (viewControllerDidFocus )]) {
201206 [self .delegate viewControllerDidFocus ];
202207 }
208+
209+ // Emit correct position after presentation
210+ [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: NO debug: @" did present" ];
203211 });
204212
205213 [self setupGestureRecognizer ];
@@ -264,22 +272,38 @@ - (void)viewDidDisappear:(BOOL)animated {
264272 }
265273}
266274
275+ - (void )viewWillLayoutSubviews {
276+ [super viewWillLayoutSubviews ];
277+
278+ if (!_isTransitioning) {
279+ _isTrackingPositionFromLayout = YES ;
280+
281+ UIViewController *presented = self.presentedViewController ;
282+
283+ // Not realtime when another controller is presented that triggers our layout
284+ BOOL hasPresentedController = presented != nil && !presented.isBeingPresented && !presented.isBeingDismissed ;
285+
286+ BOOL realtime = !hasPresentedController;
287+
288+ if (_pendingContentSizeChange) {
289+ _pendingContentSizeChange = NO ;
290+ realtime = NO ;
291+
292+ // Store resolved position after content size changes
293+ [self storeResolvedPositionForIndex: self .currentDetentIndex];
294+ }
295+
296+ [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: realtime debug: @" layout" ];
297+ }
298+ }
299+
267300- (void )viewDidLayoutSubviews {
268301 [super viewDidLayoutSubviews ];
269302
270303 if ([self .delegate respondsToSelector: @selector (viewControllerDidChangeSize: )]) {
271304 [self .delegate viewControllerDidChangeSize: self .view.frame.size];
272305 }
273306
274- UIViewController *presented = self.presentedViewController ;
275- BOOL hasPresentedController = presented != nil && !presented.isBeingPresented && !presented.isBeingDismissed ;
276-
277- if (!_isDragging && !_isTransitioning) {
278- // Update stored position for current detent (handles content size changes)
279- [self storeResolvedPositionForIndex: self .currentDetentIndex];
280- [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: hasPresentedController];
281- }
282-
283307 // Emit pending detent change after programmatic resize settles
284308 if (_pendingDetentIndex >= 0 ) {
285309 NSInteger pendingIndex = _pendingDetentIndex;
@@ -289,9 +313,14 @@ - (void)viewDidLayoutSubviews {
289313 if ([self .delegate respondsToSelector: @selector (viewControllerDidChangeDetent:position:detent: )]) {
290314 CGFloat detent = [self detentValueForIndex: pendingIndex];
291315 [self .delegate viewControllerDidChangeDetent: pendingIndex position: self .currentPosition detent: detent];
316+
317+ // Emit position for the final position
318+ [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: NO debug: @" pending detent change" ];
292319 }
293320 });
294321 }
322+
323+ _isTrackingPositionFromLayout = NO ;
295324}
296325
297326#pragma mark - Presentation Tracking (for RN Screens integration)
@@ -402,7 +431,7 @@ - (void)setupGestureRecognizer {
402431 }
403432}
404433
405- - (void )updateDraggable {
434+ - (void )setupDraggable {
406435 UIView *presentedView = self.presentedView ;
407436 if (!presentedView)
408437 return ;
@@ -432,18 +461,22 @@ - (void)handlePanGesture:(UIPanGestureRecognizer *)gesture {
432461 _isDragging = YES ;
433462 break ;
434463 case UIGestureRecognizerStateChanged:
435- [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: YES ];
464+ if (!_isTrackingPositionFromLayout) {
465+ [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: YES debug: @" drag change" ];
466+ }
436467 break ;
437468 case UIGestureRecognizerStateEnded:
438469 case UIGestureRecognizerStateCancelled: {
439470 if (!_isTransitioning) {
440471 dispatch_async (dispatch_get_main_queue (), ^{
441472 // Store resolved position when drag ends
442473 [self storeResolvedPositionForIndex: self .currentDetentIndex];
443- [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: NO ];
474+
475+ // Emit the correct position after dragging
476+ [self emitChangePositionDelegateWithPosition: self .currentPosition realtime: NO debug: @" drag end" ];
444477 });
445478 }
446-
479+
447480 _isDragging = NO ;
448481 break ;
449482 }
@@ -461,7 +494,7 @@ - (void)setupTransitionTracker {
461494 _isTransitioning = YES ;
462495
463496 CGRect dismissedFrame = CGRectMake (0 , self.screenHeight , 0 , 0 );
464- CGRect presentedFrame = CGRectMake (0 , self.presentedView . frame . origin . y , 0 , 0 );
497+ CGRect presentedFrame = CGRectMake (0 , self.currentPosition , 0 , 0 );
465498
466499 // Set starting fake view position
467500 _transitionFakeView.frame = self.isDismissing ? presentedFrame : dismissedFrame;
@@ -470,7 +503,7 @@ - (void)setupTransitionTracker {
470503 auto animation = ^(id <UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
471504 [[context containerView ] addSubview: self ->_transitionFakeView];
472505
473- // Set the fake view target position
506+ // Set ending fake view position
474507 self->_transitionFakeView .frame = self.isDismissing ? dismissedFrame : presentedFrame;
475508
476509 self->_transitioningTimer = [CADisplayLink displayLinkWithTarget: self selector: @selector (handleTransitionTracker )];
@@ -495,16 +528,17 @@ - (void)handleTransitionTracker {
495528
496529 if (self.currentPosition >= self.screenHeight ) {
497530 // Dismissing position
498- [self emitChangePositionDelegateWithPosition: layerPosition realtime: YES ];
531+ CGFloat position = fmax (_lastPosition, layerPosition);
532+ [self emitChangePositionDelegateWithPosition: position realtime: YES debug: @" transition out" ];
499533 } else {
500534 // Presenting position
501535 CGFloat position = fmax (self.currentPosition , layerPosition);
502- [self emitChangePositionDelegateWithPosition: position realtime: YES ];
536+ [self emitChangePositionDelegateWithPosition: position realtime: YES debug: @" transition in " ];
503537 }
504538 }
505539}
506540
507- - (void )emitChangePositionDelegateWithPosition : (CGFloat)position realtime : (BOOL )realtime {
541+ - (void )emitChangePositionDelegateWithPosition : (CGFloat)position realtime : (BOOL )realtime debug : ( NSString *) debug {
508542 // Use epsilon comparison to avoid missing updates due to floating point precision
509543 if (fabs (_lastPosition - position) > 0.01 ) {
510544 _lastPosition = position;
@@ -514,6 +548,9 @@ - (void)emitChangePositionDelegateWithPosition:(CGFloat)position realtime:(BOOL)
514548 if ([self .delegate respondsToSelector: @selector (viewControllerDidChangePosition:position:detent:realtime: )]) {
515549 [self .delegate viewControllerDidChangePosition: index position: position detent: detent realtime: realtime];
516550 }
551+
552+ // Debug position tracking
553+ // NSLog(@"position from %@: %f, realtime: %i", debug, position, realtime);
517554 }
518555}
519556
@@ -658,6 +695,11 @@ - (CGFloat)detentValueForIndex:(NSInteger)index {
658695
659696#pragma mark - Sheet Configuration
660697
698+ - (void )setupSheetDetentsForSizeChange {
699+ _pendingContentSizeChange = YES ;
700+ [self setupSheetDetents ];
701+ }
702+
661703- (void )setupSheetDetents {
662704 UISheetPresentationController *sheet = self.sheetPresentationController ;
663705 if (!sheet)
0 commit comments