Reputation: 125456
safeAreaInset(edge:alignment:spacing:content:)
:
The modified view is inset by the height of content, from edge, with its safe area increased by the same amount.
It appears that SwiftUI's safeAreaInset
is not imported into UIKit's safe area:
ZStack {
Color.black
UIKitView()
}
.ignoresSafeArea(edges: .top)
.safeAreaInset(edge: .top) {
Text("TOP")
.frame(minHeight: 200)
.background(Color.cyan.opacity(0.5))
}
In this example, both the black
view and the UIKitView
are laid out the same - they ignore both the safeAreaInset:top
and the status bar.
The question is: how can the UIKitView
learn about the safe area in play?
Consider the following:
struct UIKitView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> some UIViewController { ViewController() }
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
class ViewController: UIViewController {
let bgView = UILabel()
let safeView = UILabel()
override func viewDidLoad() {
bgView.backgroundColor = .red.withAlphaComponent(0.5)
self.view.addSubview(bgView)
safeView.backgroundColor = .green.withAlphaComponent(0.5)
self.view.addSubview(safeView)
}
override func viewWillLayoutSubviews() {
self.bgView.frame = self.view.bounds
self.safeView.frame = self.view.safeAreaLayoutGuide.layoutFrame
}
}
}
We now see two layers generated by the UIKitView
, one that represents the full frame of the view (red
), and one that is limited to the known safe area (green
).
What is clear now is that UIKit's safe area is constrained by the status bar, but NOT by the safeAreaInset:top
. This is surprising – how can we learn about the full top safe area in play and correctly adjust the green view to accommodate the content placed manually above it?
Upvotes: 5
Views: 582
Reputation: 119666
It seems like you mixed up some concepts.
ZStack
only stacks views on top of each other and does nothing to do with the safeArea
.
You are performing environmental layout actions inside the prebuilt UIViewController
functions with some static codes, like assigning the frame directly. So it will NOT update the UI as desired.
Try the following to see what you are looking for:
struct ContentView: View {
var body: some View {
NavigationView {
ZStack {
Color.black
UIKitView()
}
.ignoresSafeArea(edges: .top)
.navigationTitle("Hello World")
}
}
}
By adding a NavigationView
which respects the safe area, you can see that:
the SwiftUI.Color.Black
goes beyond the top
of the SafeArea
below the NavigationBar
but NOT below the bottom
of the SafeArea
The safeView
(the green one) is completely in the safeArea
as you manually set the safeAreaLayoutGuide.layoutFrame
on it, which is the portion of your view that is unobscured by bars and other content
The bgView
(the red one) is sized and placed exactly like the SwiftUI.Color.Black
. Because it is handled by the SwiftUI
layout system.
SwiftUI
control the layout, go with the frame.SwiftUI
layout and access the safe area of the environment
(which can bث the status bar or any other bars like the navigation bar or even physical objects like the notch or the dynamic island), go with the internal view's safeAreaLayoutGuide
.Hope it explains the difference.
Upvotes: 1