diff --git a/Sources/COpenSwiftUI/Shims/UIKit/UIKit_Private.h b/Sources/COpenSwiftUI/Shims/UIKit/UIKit_Private.h index 18c399afa..f242c9051 100644 --- a/Sources/COpenSwiftUI/Shims/UIKit/UIKit_Private.h +++ b/Sources/COpenSwiftUI/Shims/UIKit/UIKit_Private.h @@ -36,6 +36,9 @@ OPENSWIFTUI_ASSUME_NONNULL_BEGIN @interface UIView (OpenSwiftUI_SPI) - (instancetype)_initWithLayer:(CALayer *)layer; +- (void)_geometryChanged:(const void *)geometry forAncestor:(nullable UIView *)ancestor; +- (void)_registerForGeometryChanges; +- (void)_unregisterForGeometryChanges; - (BOOL)_shouldAnimatePropertyWithKey_openswiftui_safe_wrapper:(NSString *)key OPENSWIFTUI_SWIFT_NAME(_shouldAnimateProperty(withKey:)); - (void)_setFocusInteractionEnabled_openswiftui_safe_wrapper:(BOOL)enabled OPENSWIFTUI_SWIFT_NAME(_setFocusInteractionEnabled(_:)); @property(nonatomic, readonly, nullable) UIViewController *_viewControllerForAncestor_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_viewControllerForAncestor); diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView+Extension.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView+Extension.swift index 9e5dbb745..296220fd9 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView+Extension.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView+Extension.swift @@ -280,7 +280,18 @@ extension _UIHostingView: ViewRendererHost { } package func updateTransform() { + base.updateTransform() + + // TODO: Notify UIKit related bridges _openSwiftUIUnimplementedWarning() + + if !safeAreaRegions.contains(.container) { + invalidateProperties(.safeArea, mayDeferUpdate: false) + } + } + + package func updateTransformWithoutGeometryObservation() { + base.updateTransformWithoutGeometryObservation() } package func updateSize() { @@ -356,6 +367,11 @@ extension _UIHostingView { extension _UIHostingView: RootTransformProvider { package func rootTransform() -> ViewTransform { + if !_base.registeredForGeometryChanges { + _base.registeredForGeometryChanges = true + _registerForGeometryChanges() + } + // TODO _openSwiftUIUnimplementedWarning() return .init() } @@ -392,4 +408,3 @@ public func _makeUIHostingView(_ view: Content) -> NSObject where Conte } #endif - diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift index 60e5bff0f..372c43097 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift @@ -243,6 +243,13 @@ open class _UIHostingView: UIView, XcodeViewDebugDataProvider where Con base.layoutSubviews() } + override dynamic open func _geometryChanged( + _ geometry: UnsafeRawPointer, + forAncestor ancestor: UIView? + ) { + base._geometryChanged(geometry, forAncestor: ancestor) + } + override dynamic open var frame: CGRect { get { super.frame diff --git a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift index f406e52c6..994cef5b1 100644 --- a/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift +++ b/Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingViewBase.swift @@ -230,8 +230,30 @@ package class UIHostingViewBase { } } + @inline(__always) + func updateTransform() { + guard let uiView else { + return + } + if !viewGraph.invalidateTransform(), registeredForGeometryChanges { + uiView._unregisterForGeometryChanges() + registeredForGeometryChanges = false + } + } + package func updateTransformWithoutGeometryObservation() { - _openSwiftUIUnimplementedFailure() + guard let uiView else { + return + } + let wasRegisteredForGeometryChanges = registeredForGeometryChanges + if !viewGraph.invalidateTransform(), registeredForGeometryChanges { + uiView._unregisterForGeometryChanges() + registeredForGeometryChanges = false + } + if !wasRegisteredForGeometryChanges, registeredForGeometryChanges { + uiView._unregisterForGeometryChanges() + registeredForGeometryChanges = false + } } @inline(__always) @@ -510,7 +532,14 @@ package class UIHostingViewBase { } package func _geometryChanged(_: UnsafeRawPointer, forAncestor: UIView?) { - _openSwiftUIUnimplementedFailure() + guard let host else { + return + } + if registeredForGeometryChanges { + host.invalidateProperties(.transform, mayDeferUpdate: false) + } else if !options.contains(.registeredForGeometryChanges) { + Log.internalError("Received _geometryChanged with no registration for \(self).") + } } package func layoutSubviews() { diff --git a/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift b/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift index a07b02df9..cd8d50eb0 100644 --- a/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift +++ b/Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift @@ -377,7 +377,13 @@ extension ViewGraph { @discardableResult package func invalidateTransform() -> Bool { - _openSwiftUIUnimplementedFailure() + let rootTransform = $rootTransform + guard !rootTransform.valueState.contains(.dirty) else { + return false + } + rootTransform.invalidateValue() + delegate?.graphDidChange() + return true } }