Skip to content

Commit 5f84a6a

Browse files
Merge pull request #2461 from DataDog/gonzalezreal/RUM-10654/ios-26-navigation-bar
RUM-10654: Fix SwiftUI large title navigation bar in iOS 26 Session Replay recordings Co-authored-by: gonzalezreal <guille.gonzalez@datadoghq.com>
2 parents cb18f64 + 28cd894 commit 5f84a6a

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

DatadogSessionReplay/Sources/Recorder/ViewTreeSnapshotProducer/ViewTreeSnapshot/NodeRecorders/UINavigationBarRecorder.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,25 @@ internal struct UINavigationBarRecorder: NodeRecorder {
3636

3737
private func inferOccupiedFrame(of navigationBar: UINavigationBar, in context: ViewTreeRecordingContext) -> CGRect {
3838
var occupiedFrame = navigationBar.frame
39+
var largeTitleFrame: CGRect?
40+
3941
for subview in navigationBar.subviews {
4042
let subviewFrame = subview.convert(subview.bounds, to: context.coordinateSpace)
43+
44+
if subview.isNavigationBarLargeTitleView {
45+
largeTitleFrame = subviewFrame
46+
}
47+
4148
occupiedFrame = occupiedFrame.union(subviewFrame)
4249
}
50+
51+
if #available(iOS 26, *), navigationBar.isSwiftUINavigationBar, let largeTitleFrame {
52+
// For SwiftUI navigation bars, exclude the large title view from `occupiedFrame`
53+
// to prevent occluding the large title that's rendered as a sibling view
54+
let height = max(0, min(largeTitleFrame.height, occupiedFrame.height))
55+
occupiedFrame = occupiedFrame.inset(by: .init(top: 0, left: 0, bottom: height, right: 0))
56+
}
57+
4358
return occupiedFrame
4459
}
4560

@@ -88,4 +103,26 @@ internal struct UINavigationBarWireframesBuilder: NodeWireframesBuilder {
88103
]
89104
}
90105
}
106+
107+
extension UIView {
108+
private enum Constants {
109+
static let UIKitNavigationBarClass: AnyClass? = NSClassFromString("SwiftUI.UIKitNavigationBar")
110+
static let NavigationBarLargeTitleView: AnyClass? = NSClassFromString("UIKit.NavigationBarLargeTitleView")
111+
}
112+
113+
fileprivate var isSwiftUINavigationBar: Bool {
114+
guard let cls = Constants.UIKitNavigationBarClass else {
115+
return false
116+
}
117+
return type(of: self).isSubclass(of: cls)
118+
}
119+
120+
fileprivate var isNavigationBarLargeTitleView: Bool {
121+
guard let cls = Constants.NavigationBarLargeTitleView else {
122+
return false
123+
}
124+
return type(of: self).isSubclass(of: cls)
125+
}
126+
}
127+
91128
#endif

0 commit comments

Comments
 (0)