I want to manually set the frame height of a view in SwiftUI to the size of the safe area of the screen. It's easy to get the bounds of the screen (UIScreen.main.bounds
), but I can't find a way to access the size of the safe area.
So, to summarize, ignoring safe areas in SwiftUI is just a matter of calling a simple view modifier. Apply it whenever necessary, and expand the safe area of your views in order build an interface the way you like it.
Fresh out of WWDC21, safeAreaInset() is a brand new SwiftUI view modifier, which lets us define views that become part of the observed safe area.
Probably the simplest way to build a list is to create a new SwiftUI view and wrap the Hello World text in a List: struct StaticListView: View { var body: some View { List { Text("Hello, world!") } } } To add more items to the list, we can just add another line: List { Text("Hello, world!") Text("Hello, SwiftUI!") }
You can use a GeometryReader
to access the safe area.
See: https://developer.apple.com/documentation/swiftui/geometryreader.
struct ContentView : View {
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
Color.red
.frame(
width: geometry.size.width,
height: geometry.safeAreaInsets.top,
alignment: .center
)
.aspectRatio(contentMode: ContentMode.fit)
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
But FYI: The safe area is not a size. It is an EdgeInsets
.
If you use edgesIgnoringSafeArea
on an parentView and you want to access the device UISafeAreaInsets
you can do the following:
Code
private struct SafeAreaInsetsKey: EnvironmentKey {
static var defaultValue: EdgeInsets {
(UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.safeAreaInsets ?? .zero).insets
}
}
extension EnvironmentValues {
var safeAreaInsets: EdgeInsets {
self[SafeAreaInsetsKey.self]
}
}
private extension UIEdgeInsets {
var insets: EdgeInsets {
EdgeInsets(top: top, leading: left, bottom: bottom, trailing: right)
}
}
Usage
struct MyView: View {
@Environment(\.safeAreaInsets) private var safeAreaInsets
var body: some View {
Text("Ciao")
.padding(safeAreaInsets)
}
}
UIApplication.shared.windows is deprecated, you can now use connectedScenes:
import SwiftUI
extension UIApplication {
var keyWindow: UIWindow? {
connectedScenes
.compactMap {
$0 as? UIWindowScene
}
.flatMap {
$0.windows
}
.first {
$0.isKeyWindow
}
}
}
private struct SafeAreaInsetsKey: EnvironmentKey {
static var defaultValue: EdgeInsets {
UIApplication.shared.keyWindow?.safeAreaInsets.swiftUiInsets ?? EdgeInsets()
}
}
extension EnvironmentValues {
var safeAreaInsets: EdgeInsets {
self[SafeAreaInsetsKey.self]
}
}
private extension UIEdgeInsets {
var swiftUiInsets: EdgeInsets {
EdgeInsets(top: top, leading: left, bottom: bottom, trailing: right)
}
}
And then use Environment property in your View to get safe area insets:
@Environment(\.safeAreaInsets) private var safeAreaInsets
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With