Yanıtlar:
Bunu dene :
In Objective 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
için her zaman nil
öylesine değiştirdim windows[0]
ve ?
isteğe bağlı zincirleme kaldırıldı , sonra çalıştı.
Düzen kılavuzları arasındaki yüksekliği elde etmek için yapmanız gereken
let guide = view.safeAreaLayoutGuide
let height = guide.layoutFrame.size.height
Yani full frame height = 812.0
,safe area height = 734.0
Aşağıda yeşil görünümün guide.layoutFrame
UIApplication.sharedApplication.keyWindow.safeAreaLayoutGuide.layoutFrame
güvenli bir çerçeveye sahip kullanıyorum .
Swift 4, 5
Bir görünümü güvenli bir alan bağlantısına sabitlemek için kısıtlamalar kullanarak görünüm denetleyicisinin yaşam döngüsünün herhangi bir yerinde yapılabilir, çünkü bunlar API tarafından sıraya alınır ve görünüm belleğe yüklendikten sonra işlenir. Ancak, güvenli alan değerlerinin elde edilmesi, bir görünüm denetleyicisinin yaşam döngüsünün sonuna doğru beklemeyi gerektirir viewDidLayoutSubviews()
.
Bu, herhangi bir görünüm denetleyicisine takılır:
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
}
API'nin nasıl tasarlandığı ve daha da önemlisi, cihaz yönlendirme değişiklikleri gibi tüm görünüm değişiklikleri sırasında değerler güncellendiğinden, bu yöntemi pencereden çıkarmak için (mümkünse) tercih ederim.
Ancak, bazı özel sunulan görünüm denetleyicileri yukarıdaki yöntemi kullanamazsınız (geçici kapsayıcı görünümlerinde olduğundan şüpheleniyorum). Bu gibi durumlarda, değerleri geçerli görünüm denetleyicisinin yaşam döngüsünde her zaman kullanılabilecek kök görünüm denetleyicisinden alabilirsiniz.
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
(birden çok kez çağrılabilir), burada bile çalışacak bir çözüm var viewDidLoad
: stackoverflow.com/a/53864017/7767664
Buradaki diğer cevapların hiçbiri benim için işe yaramadı, ama bu işe yaramadı.
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
}
Buradaki tüm cevaplar faydalı, Yardım sunan herkese teşekkürler.
Ancak güvenli alan konusunun iyi belgelenmiş görünmeyecek şekilde biraz karışık olduğunu gördüğüm gibi.
Ben burada özetleyecek Yani mümkün olduğunca pelte gibi kolay anlaşılması için safeAreaInsets
, safeAreaLayoutGuide
ve LayoutGuide
.
İOS 7'de Apple topLayoutGuide
ve bottomLayoutGuide
özelliklerini tanıttı, UIViewController
İçeriğinizin durum, gezinme veya sekme çubuğu gibi UIKit çubukları tarafından gizlenmesini önlemek için kısıtlamalar oluşturmanıza izin verdiler. Bu düzen kılavuzlarıyla, içeriğe ilişkin kısıtlamaları belirlemek ve bundan kaçınmak mümkün oldu. üst veya alt gezinme öğeleri (UIKit çubukları, durum çubuğu, gezinme veya sekme çubuğu…) tarafından gizlenmesini sağlar.
Yani, örneğin bir tableView üst ekrandan başlamak istiyorsanız böyle bir şey yaptınız:
self.tableView.contentInset = UIEdgeInsets(top: -self.topLayoutGuide.length, left: 0, bottom: 0, right: 0)
İOS 11'de Apple, bu özellikleri tek bir güvenli alan düzeni kılavuzuyla değiştirerek bu özellikleri kullanımdan kaldırmıştır
Apple'a göre güvenli alan
Güvenli alanlar, görünümlerinizi genel arayüzün görünür kısmına yerleştirmenize yardımcı olur. UIKit tanımlı görünüm denetleyicileri özel görünümleri içeriğinizin üzerine yerleştirebilir. Örneğin, bir gezinti denetleyicisi temel görünüm denetleyicisinin içeriğinin üstünde bir gezinme çubuğu görüntüler. Bu tür görüşler kısmen şeffaf olsa bile, yine de altındaki içeriği kapatırlar. TVOS'ta güvenli alan, ekranın çerçevesinin kapladığı alanı temsil eden ekranın aşırı tarama eklerini de içerir.
Aşağıda, iPhone 8 ve iPhone X serilerinde vurgulanan güvenli bir alan:
safeAreaLayoutGuide
Bir özelliktirUIView
Yüksekliğini elde etmek için safeAreaLayoutGuide
:
extension UIView {
var safeAreaHeight: CGFloat {
if #available(iOS 11, *) {
return safeAreaLayoutGuide.layoutFrame.size.height
}
return bounds.height
}
}
Bu, resminizdeki Ok yüksekliğini döndürecektir.
Şimdi, üst "çentik" ve alt ana ekran gösterge yüksekliklerini almaya ne dersiniz?
Burada kullanacağız safeAreaInsets
Bir görünümün güvenli alanı, gezinme çubukları, sekme çubukları, araç çubukları ve bir görünüm denetleyicisinin görünümünü gizleyen diğer ataların kapsamadığı alanı yansıtır. (TvOS'ta, güvenli alan ekranın çerçevesi tarafından kaplanmayan alanı yansıtır.) Bu özellikteki iç metinleri görünümün sınır dikdörtgenine uygulayarak görünüm için güvenli alanı elde edersiniz. Görünüm şu anda bir görünüm hiyerarşisine yüklenmemişse veya henüz ekranda görünmüyorsa, bu özellikteki kenar iç metinleri 0'dır.
Aşağıda güvensiz alan ve iPhone 8 ve iPhone X-Series'in birindeki kenarlardan olan mesafe gösterilecektir.
Şimdi, gezinme çubuğu eklendiyse
Peki, şimdi güvensiz alan yüksekliği nasıl elde edilir? kullanacağızsafeAreaInset
İşte çözümler ancak önemli bir şeyde farklılık gösterir,
Birincisi:
self.view.safeAreaInsets
Bu, EdgeInsets'i döndürecek, artık üstleri ve alt kısımları girerek girişleri öğrenebilirsiniz,
İkinci:
UIApplication.shared.windows.first{$0.isKeyWindow }?.safeAreaInsets
Birincisi görünüm eklerini alırsınız, bu nedenle bir gezinme çubuğu varsa dikkate alınır, ancak ikincisi pencerenin safeAreaInsets'e erişirsiniz, böylece gezinme çubuğu dikkate alınmaz
Swift 5, Xcode 11.4
`UIApplication.shared.keyWindow`
Kullanımdan kaldırma uyarısı verecektir. '' keyWindow 'iOS 13.0'da kullanımdan kaldırıldı: Bağlı sahneler nedeniyle bağlı tüm sahnelerde bir anahtar pencere döndürdüğü için birden fazla sahneyi destekleyen uygulamalar için kullanılmamalıdır. Ben bu yolu kullanıyorum.
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 })
}
}
safeAreaLayoutGuide Görünüm ekranda görünür olduğunda, bu kılavuz görünümün gezinme çubukları, sekme çubukları, araç çubukları ve diğer ata görünümleri tarafından kapsanmayan kısmını yansıtır. (TvOS'ta, güvenli alan ekranın çerçevesini kaplamamış alanı yansıtır.) Görünüm şu anda bir görünüm hiyerarşisine yüklenmemişse veya henüz ekranda görünmüyorsa, düzen kılavuzu kenarları görünümün kenarlarına eşittir.
Sonra ekran görüntüsünde kırmızı ok yüksekliğini elde etmek için:
self.safeAreaLayoutGuide.layoutFrame.size.height
Objective-C keyWindow nil değerine sahip olduğunda kimin sorunu vardı . Yukarıdaki kodu viewDidAppear'a koymanız yeterlidir (viewDidLoad içinde değil)
Swift 5 Uzantısı
Bu bir Uzantı olarak kullanılabilir ve şunlarla çağrılabilir: 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
}
}
UIApplication'nın genişletilmesi isteğe bağlıdır, UIView'in veya tercih edilenin bir uzantısı veya muhtemelen daha iyi bir global işlev olabilir.
Daha yuvarlak bir yaklaşım
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
}
}
Yatay moda geçenler için, en güncel değerleri almak için rotasyondan sonra viewSafeAreaInsetsDidChange kullandığınızdan emin olmalısınız :
private var safeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
override func viewSafeAreaInsetsDidChange() {
if #available(iOS 11.0, *) {
safeAreaInsets = UIApplication.shared.keyWindow!.safeAreaInsets
}
}