Antworten:
Versuche dies :
In Ziel C.
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.keyWindow;
CGFloat topPadding = window.safeAreaInsets.top;
CGFloat bottomPadding = window.safeAreaInsets.bottom;
}
In Swift
if #available(iOS 11.0, *) {
let window = UIApplication.shared.keyWindow
let topPadding = window?.safeAreaInsets.top
let bottomPadding = window?.safeAreaInsets.bottom
}
keyWindow
war es immer nil
so, dass ich es geändert windows[0]
und ?
aus der optionalen Verkettung entfernt habe, dann hat es funktioniert.
Um die Höhe zwischen den Layout-Anleitungen zu ermitteln, müssen Sie dies nur tun
let guide = view.safeAreaLayoutGuide
let height = guide.layoutFrame.size.height
Also full frame height = 812.0
,safe area height = 734.0
Unten sehen Sie das Beispiel, in dem die grüne Ansicht einen Rahmen von hat guide.layoutFrame
UIApplication.sharedApplication.keyWindow.safeAreaLayoutGuide.layoutFrame
, was den sicheren Rahmen hat.
Swift 4, 5
Das Anheften einer Ansicht an einen sicheren Bereichsanker mithilfe von Einschränkungen kann an einer beliebigen Stelle im Lebenszyklus des Ansichtscontrollers erfolgen, da diese von der API in die Warteschlange gestellt und nach dem Laden der Ansicht in den Speicher verarbeitet werden. Das Abrufen von Sicherheitsbereichswerten erfordert jedoch das Warten gegen Ende des Lebenszyklus eines View Controllers, zviewDidLayoutSubviews()
.
Dies wird an jeden View Controller angeschlossen:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topSafeArea: CGFloat
let bottomSafeArea: CGFloat
if #available(iOS 11.0, *) {
topSafeArea = view.safeAreaInsets.top
bottomSafeArea = view.safeAreaInsets.bottom
} else {
topSafeArea = topLayoutGuide.length
bottomSafeArea = bottomLayoutGuide.length
}
// safe area values are now available to use
}
Ich bevorzuge diese Methode, um sie aus dem Fenster zu entfernen (wenn möglich), da die API so entworfen wurde und, was noch wichtiger ist, die Werte bei allen Ansichtsänderungen aktualisiert werden, z. B. bei Änderungen der Geräteorientierung.
Einige benutzerdefinierte Ansichtssteuerungen können die oben beschriebene Methode jedoch nicht verwenden (ich vermute, weil sie sich in vorübergehenden Containeransichten befinden). In solchen Fällen können Sie die Werte vom Root-View-Controller abrufen, der immer überall im Lebenszyklus des aktuellen View-Controllers verfügbar ist.
anyLifecycleMethod()
guard let root = UIApplication.shared.keyWindow?.rootViewController else {
return
}
let topSafeArea: CGFloat
let bottomSafeArea: CGFloat
if #available(iOS 11.0, *) {
topSafeArea = root.view.safeAreaInsets.top
bottomSafeArea = root.view.safeAreaInsets.bottom
} else {
topSafeArea = root.topLayoutGuide.length
bottomSafeArea = root.bottomLayoutGuide.length
}
// safe area values are now available to use
}
viewDidLayoutSubviews
(die mehrfach aufgerufen werden kann). Hier ist eine Lösung, die auch in viewDidLoad
folgenden Fällen
Keine der anderen Antworten hier hat für mich funktioniert, aber das hat funktioniert.
var topSafeAreaHeight: CGFloat = 0
var bottomSafeAreaHeight: CGFloat = 0
if #available(iOS 11.0, *) {
let window = UIApplication.shared.windows[0]
let safeFrame = window.safeAreaLayoutGuide.layoutFrame
topSafeAreaHeight = safeFrame.minY
bottomSafeAreaHeight = window.frame.maxY - safeFrame.maxY
}
Alle Antworten hier sind hilfreich. Vielen Dank an alle, die Hilfe angeboten haben.
Wie ich jedoch sehe, ist das Thema des sicheren Bereichs etwas verwirrt, was nicht gut dokumentiert zu sein scheint.
Deshalb werde ich es hier so gut wie möglich zusammenfassen, um es leicht verständlich zu machen safeAreaInsets
, safeAreaLayoutGuide
und LayoutGuide
.
In iOS 7 führte Apple die Eigenschaften topLayoutGuide
und bottomLayoutGuide
in einUIViewController
. Sie ermöglichten es Ihnen, Einschränkungen zu erstellen, um zu verhindern, dass Ihre Inhalte durch UIKit-Leisten wie Status, Navigation oder Registerkartenleiste ausgeblendet werden. Mit diesen Layout-Anleitungen konnten Sie Einschränkungen für den Inhalt festlegen und diese vermeiden durch obere oder untere Navigationselemente (UIKit-Leisten, Statusleiste, Navigations- oder Registerkartenleiste…) ausgeblendet werden.
Wenn Sie beispielsweise eine Tabellenansicht erstellen möchten, die vom oberen Bildschirm aus beginnt, haben Sie Folgendes getan:
self.tableView.contentInset = UIEdgeInsets(top: -self.topLayoutGuide.length, left: 0, bottom: 0, right: 0)
In iOS 11 hat Apple diese Eigenschaften abgelehnt und sie durch eine einzige Anleitung zum Layout sicherer Bereiche ersetzt
Sicherer Bereich laut Apple
Mithilfe sicherer Bereiche können Sie Ihre Ansichten im sichtbaren Bereich der gesamten Benutzeroberfläche platzieren. UIKit-definierte Ansichts-Controller können spezielle Ansichten über Ihren Inhalten platzieren. Ein Navigationscontroller zeigt beispielsweise eine Navigationsleiste über dem Inhalt des zugrunde liegenden Ansichtscontrollers an. Selbst wenn solche Ansichten teilweise transparent sind, verschließen sie den darunter liegenden Inhalt. In tvOS enthält der sichere Bereich auch die Overscan-Einsätze des Bildschirms, die den Bereich darstellen, der von der Bildschirmblende abgedeckt wird.
Unten ein sicherer Bereich, der in iPhone 8 und iPhone X-Serie hervorgehoben wird:
Das safeAreaLayoutGuide
ist eine Eigenschaft vonUIView
So erhalten Sie die Höhe von safeAreaLayoutGuide
:
extension UIView {
var safeAreaHeight: CGFloat {
if #available(iOS 11, *) {
return safeAreaLayoutGuide.layoutFrame.size.height
}
return bounds.height
}
}
Dadurch wird die Höhe des Pfeils in Ihrem Bild zurückgegeben.
Was ist nun mit der Anzeige der oberen "Kerbe" und der unteren Höhe des Startbildschirms?
Hier werden wir die verwenden safeAreaInsets
Der sichere Bereich einer Ansicht spiegelt den Bereich wider, der nicht von Navigationsleisten, Registerkartenleisten, Symbolleisten und anderen Vorfahren abgedeckt wird, die die Ansicht eines Ansichtscontrollers verdecken. (In tvOS spiegelt der sichere Bereich den Bereich wider, der nicht von der Bildschirmblende abgedeckt wird.) Sie erhalten den sicheren Bereich für eine Ansicht, indem Sie die Einfügungen in dieser Eigenschaft auf das Begrenzungsrechteck der Ansicht anwenden. Wenn die Ansicht derzeit nicht in einer Ansichtshierarchie installiert ist oder noch nicht auf dem Bildschirm angezeigt wird, sind die Kanteneinfügungen in dieser Eigenschaft 0.
Im Folgenden werden der unsichere Bereich und der Abstand zu den Kanten des iPhone 8 und eines der iPhone X-Serien angezeigt.
Nun, wenn Navigationsleiste hinzugefügt
Wie kann man nun die Höhe des unsicheren Bereichs ermitteln? Wir werden die verwendensafeAreaInset
Hier sind Lösungen, die sich jedoch in einer wichtigen Sache unterscheiden:
Erster:
self.view.safeAreaInsets
Dadurch werden die EdgeInsets zurückgegeben. Sie können jetzt oben und unten darauf zugreifen, um die Insets zu kennen.
Das Zweite:
UIApplication.shared.windows.first{$0.isKeyWindow }?.safeAreaInsets
Beim ersten Mal nehmen Sie die Ansichtseinfügungen auf. Wenn also eine Navigationsleiste vorhanden ist, wird diese berücksichtigt. Beim zweiten Mal greifen Sie jedoch auf die safeAreaInsets des Fensters zu, sodass die Navigationsleiste nicht berücksichtigt wird
safeAreaLayoutGuide Wenn die Ansicht auf dem Bildschirm angezeigt wird, spiegelt diese Anleitung den Teil der Ansicht wider, der nicht von Navigationsleisten, Registerkartenleisten, Symbolleisten und anderen Vorfahrenansichten abgedeckt wird. (In tvOS spiegelt der sichere Bereich den Bereich wider, der die Bildschirmblende nicht abdeckt.) Wenn die Ansicht derzeit nicht in einer Ansichtshierarchie installiert ist oder auf dem Bildschirm noch nicht sichtbar ist, entsprechen die Kanten der Layoutführung den Kanten der Ansicht.
Um die Höhe des roten Pfeils im Screenshot zu ermitteln, gilt Folgendes:
self.safeAreaLayoutGuide.layoutFrame.size.height
Swift 5, Xcode 11.4
`UIApplication.shared.keyWindow`
Es wird eine Abwertungswarnung ausgegeben. '' keyWindow '' war in iOS 13.0 veraltet: Sollte nicht für Anwendungen verwendet werden, die mehrere Szenen unterstützen, da aufgrund verbundener Szenen ein Schlüsselfenster für alle verbundenen Szenen zurückgegeben wird. Ich benutze diesen Weg.
extension UIView {
var safeAreaBottom: CGFloat {
if #available(iOS 11, *) {
if let window = UIApplication.shared.keyWindowInConnectedScenes {
return window.safeAreaInsets.bottom
}
}
return 0
}
var safeAreaTop: CGFloat {
if #available(iOS 11, *) {
if let window = UIApplication.shared.keyWindowInConnectedScenes {
return window.safeAreaInsets.top
}
}
return 0
}
}
extension UIApplication {
var keyWindowInConnectedScenes: UIWindow? {
return windows.first(where: { $0.isKeyWindow })
}
}
Objective-C Wer hatte das Problem , wenn keyWindow gleich ist Null . Fügen Sie einfach den obigen Code in viewDidAppear ein (nicht in viewDidLoad).
Swift 5-Erweiterung
Dies kann als Erweiterung verwendet und aufgerufen werden mit: UIApplication.topSafeAreaHeight
extension UIApplication {
static var topSafeAreaHeight: CGFloat {
var topSafeAreaHeight: CGFloat = 0
if #available(iOS 11.0, *) {
let window = UIApplication.shared.windows[0]
let safeFrame = window.safeAreaLayoutGuide.layoutFrame
topSafeAreaHeight = safeFrame.minY
}
return topSafeAreaHeight
}
}
Die Erweiterung von UIApplication ist optional, kann eine Erweiterung von UIView sein oder was auch immer bevorzugt wird, oder wahrscheinlich sogar eine globale Funktion.
Ein runderer Ansatz
import SnapKit
let containerView = UIView()
containerView.backgroundColor = .red
self.view.addSubview(containerView)
containerView.snp.remakeConstraints { (make) -> Void in
make.width.top.equalToSuperView()
make.top.equalTo(self.view.safeArea.top)
make.bottom.equalTo(self.view.safeArea.bottom)
}
extension UIView {
var safeArea: ConstraintBasicAttributesDSL {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.snp
}
return self.snp
}
var isIphoneX: Bool {
if #available(iOS 11.0, *) {
if topSafeAreaInset > CGFloat(0) {
return true
} else {
return false
}
} else {
return false
}
}
var topSafeAreaInset: CGFloat {
let window = UIApplication.shared.keyWindow
var topPadding: CGFloat = 0
if #available(iOS 11.0, *) {
topPadding = window?.safeAreaInsets.top ?? 0
}
return topPadding
}
var bottomSafeAreaInset: CGFloat {
let window = UIApplication.shared.keyWindow
var bottomPadding: CGFloat = 0
if #available(iOS 11.0, *) {
bottomPadding = window?.safeAreaInsets.bottom ?? 0
}
return bottomPadding
}
}