diff --git a/modules/bottom-sheet/ios/SheetView.swift b/modules/bottom-sheet/ios/SheetView.swift index 360c7a9101..8d9f07da58 100644 --- a/modules/bottom-sheet/ios/SheetView.swift +++ b/modules/bottom-sheet/ios/SheetView.swift @@ -8,6 +8,9 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate { private var innerView: UIView? private var touchHandler: RCTTouchHandler? + // Native content height observation (eliminates JS bridge round-trip) + private var contentHeightObservation: NSKeyValueObservation? + // Events private let onAttemptDismiss = EventDispatcher() private let onSnapPointChange = EventDispatcher() @@ -106,6 +109,8 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate { } private func destroy() { + self.contentHeightObservation?.invalidate() + self.contentHeightObservation = nil self.isClosing = false self.isOpen = false self.sheetVc = nil @@ -147,6 +152,7 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate { self.sheetVc = sheetVc self.isOpening = true + self.startObservingContentHeight() rvc.present(sheetVc, animated: true) { [weak self] in self?.isOpening = false @@ -154,6 +160,27 @@ class SheetView: ExpoView, UISheetPresentationControllerDelegate { } } + // Observe the content view's bounds via KVO so that height changes are detected + // purely on the native side, without a JS bridge round-trip through onLayout. + private func startObservingContentHeight() { + self.contentHeightObservation?.invalidate() + + guard let contentView = self.innerView?.subviews.first else { return } + + self.contentHeightObservation = contentView.observe( + \.bounds, + options: [.old, .new] + ) { [weak self] _, change in + guard let self = self, + (self.isOpen || self.isOpening) && !self.isClosing, + let oldBounds = change.oldValue, + let newBounds = change.newValue, + oldBounds.height != newBounds.height, + newBounds.height > 0 else { return } + self.updateLayout() + } + } + func updateLayout() { // Allow updates either when identifiers match OR when prevLayoutDetentIdentifier is nil (first real content update) if self.prevLayoutDetentIdentifier == self.selectedDetentIdentifier || self.prevLayoutDetentIdentifier == nil, diff --git a/modules/bottom-sheet/src/BottomSheetNativeComponent.tsx b/modules/bottom-sheet/src/BottomSheetNativeComponent.tsx index 0fa4c8aa23..788abf9d9d 100644 --- a/modules/bottom-sheet/src/BottomSheetNativeComponent.tsx +++ b/modules/bottom-sheet/src/BottomSheetNativeComponent.tsx @@ -126,9 +126,9 @@ export class BottomSheetNativeComponent extends React.Component< // a console.log() - just sending the log to the CLI is enough. // TODO: Get to the bottom of this and fix it properly! -sfn setTimeout(() => this.updateLayout()) - } else { - this.updateLayout() } + // iOS: content height changes are observed natively via KVO on + // the content view's bounds, so no JS bridge round-trip needed. }} />