Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access safe area size in SwiftUI?

Tags:

ios

swift

swiftui

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.

like image 202
M. Koot Avatar asked Jul 19 '19 16:07

M. Koot


People also ask

How do I ignore top safe area in SwiftUI?

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.

What is Safeareainsets?

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.

How do I create a list in SwiftUI?

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!") }


3 Answers

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.

like image 136
Ugo Arangino Avatar answered Oct 23 '22 18:10

Ugo Arangino


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)
    }
}
like image 31
Lorenzo Fiamingo Avatar answered Oct 23 '22 16:10

Lorenzo Fiamingo


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
like image 23
Mirko Avatar answered Oct 23 '22 17:10

Mirko