[英]How to access safe area size in SwiftUI?
我想手动将 SwiftUI 中视图的框架高度设置为屏幕安全区域的大小。 很容易获得屏幕的边界( UIScreen.main.bounds
),但我找不到访问安全区域大小的方法。
您可以使用GeometryReader
访问安全区域。
请参阅: 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)
}
}
但仅供参考:安全区域不是大小。 它是一个EdgeInsets
。
如果您在edgesIgnoringSafeArea
上使用 edgesIgnoringSafeArea 并且想要访问设备UISafeAreaInsets
您可以执行以下操作:
代码
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)
}
}
用法
struct MyView: View {
@Environment(\.safeAreaInsets) private var safeAreaInsets
var body: some View {
Text("Ciao")
.padding(safeAreaInsets)
}
}
UIApplication.shared.windows 已弃用,您现在可以使用 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)
}
}
然后在 View 中使用 Environment 属性来获取安全区域插图:
@Environment(\.safeAreaInsets) private var safeAreaInsets
不知道为什么接受的答案使用顶部插图作为放置在底部视图下方的视图 - 这些不一样。 此外,如果您更正此“错字”,您将看到在GeometryReader
上调用的edgesIgnoringSafeArea
将相应的值归零。 看起来在 iOS 13 上并非如此,但现在是这样,因此您需要在GeometryReader
子级上调用edgesIgnoringSafeArea
,并且此代码在 iOS 13 上仍可按预期工作:
GeometryReader { geometry in
VStack {
Spacer()
Color.red
.frame(
width: geometry.size.width,
height: geometry.safeAreaInsets.bottom,
alignment: .center
)
.aspectRatio(contentMode: ContentMode.fit)
}
.edgesIgnoringSafeArea(.bottom)
}
您还可以创建自定义EnvironmentValue
并从“初始View
”传递安全区域插图。 这对我来说非常有效!
EnvironmentValue
private struct SafeAreaInsetsEnvironmentKey: EnvironmentKey {
static let defaultValue: (top: CGFloat, bottom: CGFloat) = (0, 0)
}
extension EnvironmentValues {
var safeAreaInsets: (top: CGFloat, bottom: CGFloat) {
get { self[SafeAreaInsetsEnvironmentKey.self] }
set { self[SafeAreaInsetsEnvironmentKey.self] = newValue }
}
}
这个想法是在任何潜在的View
父级使用.edgesIgnoringSafeArea
之前执行此操作,这是它工作所必需的。 例如:
@main
struct YourApp: App {
@State private var safeAreaInsets: (top: CGFloat, bottom: CGFloat) = (0, 0)
var body: some Scene {
WindowGroup {
ZStack {
GeometryReader { proxy in
Color.clear.onAppear {
safeAreaInsets = (proxy.safeAreaInsets.top, proxy.safeAreaInsets.bottom)
}
}
ContentView()
.environment(\.safeAreaInsets, safeAreaInsets)
}
}
}
}
struct SomeChildView: View {
@Environment(\.safeAreaInsets) var safeAreaInsets
...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.