Jawaban:
Coba ini :
Dalam Tujuan C
if (@available(iOS 11.0, *)) {
UIWindow *window = UIApplication.sharedApplication.keyWindow;
CGFloat topPadding = window.safeAreaInsets.top;
CGFloat bottomPadding = window.safeAreaInsets.bottom;
}
Dalam Swift
if #available(iOS 11.0, *) {
let window = UIApplication.shared.keyWindow
let topPadding = window?.safeAreaInsets.top
let bottomPadding = window?.safeAreaInsets.bottom
}
keyWindow
selalu nil
jadi saya mengubahnya windows[0]
dan menghapus ?
dari chaining opsional, lalu berhasil.
Untuk mendapatkan ketinggian antara panduan tata letak yang baru saja Anda lakukan
let guide = view.safeAreaLayoutGuide
let height = guide.layoutFrame.size.height
Jadi full frame height = 812.0
,safe area height = 734.0
Di bawah ini adalah contoh di mana tampilan hijau memiliki bingkai guide.layoutFrame
UIApplication.sharedApplication.keyWindow.safeAreaLayoutGuide.layoutFrame
, yang memang memiliki kerangka aman.
Cepat 4, 5
Untuk menyematkan tampilan ke jangkar area aman menggunakan kendala dapat dilakukan di mana saja dalam siklus hidup pengontrol tampilan karena mereka antri oleh API dan ditangani setelah tampilan dimasukkan ke dalam memori. Namun, mendapatkan nilai area aman memerlukan menunggu menjelang akhir siklus hidup pengontrol tampilan viewDidLayoutSubviews()
.
Ini dihubungkan ke pengontrol tampilan apa pun:
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
}
Saya lebih suka metode ini untuk mengeluarkannya dari jendela (bila memungkinkan) karena ini adalah cara API dirancang dan, yang lebih penting, nilai diperbarui selama semua perubahan tampilan, seperti perubahan orientasi perangkat.
Namun, beberapa pengendali tampilan khusus yang disajikan tidak dapat menggunakan metode di atas (saya curiga karena mereka berada dalam tampilan wadah sementara). Dalam kasus seperti itu, Anda bisa mendapatkan nilai dari pengontrol tampilan root, yang akan selalu tersedia di mana saja dalam siklus hidup pengontrol tampilan saat ini.
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
(yang bisa disebut berkali-kali), inilah solusi yang akan berfungsi bahkan di viewDidLoad
: stackoverflow.com/a/53864017/7767664
Tidak ada jawaban lain di sini yang berfungsi untuk saya, tetapi ini berhasil.
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
}
Semua jawaban di sini sangat membantu, Terima kasih kepada semua orang yang menawarkan bantuan.
Namun seperti yang saya lihat bahwa topik area aman sedikit bingung yang sepertinya tidak terdokumentasi dengan baik.
Jadi saya akan meringkasnya di sini sebagai bubur mungkin untuk membuatnya mudah dimengerti safeAreaInsets
, safeAreaLayoutGuide
dan LayoutGuide
.
Di iOS 7, Apple memperkenalkan topLayoutGuide
dan bottomLayoutGuide
properti di UIViewController
, Mereka memungkinkan Anda untuk membuat batasan untuk menjaga konten Anda agar tidak disembunyikan oleh bilah UIKit seperti status, navigasi, atau bilah tab. Mungkin saja dengan panduan tata letak ini untuk menentukan batasan pada konten, menghindarinya disembunyikan oleh elemen navigasi atas atau bawah (bilah UIKit, bilah status, nav atau bilah tab ...).
Jadi misalnya jika Anda ingin membuat tableView dimulai dari layar atas Anda telah melakukan sesuatu seperti itu:
self.tableView.contentInset = UIEdgeInsets(top: -self.topLayoutGuide.length, left: 0, bottom: 0, right: 0)
Di iOS 11 Apple telah menghentikan properti ini menggantikannya dengan panduan tata letak area aman tunggal
Area aman menurut Apple
Area aman membantu Anda menempatkan tampilan dalam bagian yang terlihat dari keseluruhan antarmuka. Pengontrol tampilan yang ditentukan UIKit dapat memposisikan tampilan khusus di atas konten Anda. Misalnya, pengontrol navigasi menampilkan bilah navigasi di atas konten pengontrol tampilan yang mendasarinya. Bahkan ketika pandangan semacam itu sebagian transparan, mereka masih menyumbat konten yang ada di bawahnya. Di tvOS, area aman juga mencakup insets overscan layar, yang mewakili area yang dicakup oleh bezel layar.
Di bawah, area aman yang disorot di iPhone 8 dan iPhone X-series:
Ini safeAreaLayoutGuide
adalah properti dariUIView
Untuk mendapatkan ketinggian safeAreaLayoutGuide
:
extension UIView {
var safeAreaHeight: CGFloat {
if #available(iOS 11, *) {
return safeAreaLayoutGuide.layoutFrame.size.height
}
return bounds.height
}
}
Itu akan mengembalikan ketinggian Panah di gambar Anda.
Sekarang, bagaimana dengan mendapatkan tinggi "takik" dan ketinggian indikator layar beranda bawah?
Di sini kita akan menggunakan safeAreaInsets
Area tampilan yang aman mencerminkan area yang tidak tercakup oleh bilah navigasi, bilah tab, bilah alat, dan leluhur lainnya yang mengaburkan pandangan pengontrol tampilan. (Di tvOS, area aman mencerminkan area yang tidak tercakup oleh bezel layar.) Anda mendapatkan area aman untuk tampilan dengan menerapkan insets di properti ini ke persegi panjang batas tampilan. Jika tampilan saat ini tidak diinstal dalam hierarki tampilan, atau belum terlihat di layar, insets tepi pada properti ini adalah 0.
Berikut ini akan menunjukkan area tidak aman dan ada jarak dari tepi pada iPhone 8 dan salah satu dari iPhone X-Series.
Sekarang, jika bilah navigasi ditambahkan
Jadi, sekarang bagaimana cara mendapatkan ketinggian area yang tidak aman? kami akan menggunakansafeAreaInset
Berikut adalah solusi namun mereka berbeda dalam hal yang penting,
Pertama:
self.view.safeAreaInsets
Itu akan mengembalikan EdgeInsets, Anda sekarang dapat mengakses bagian atas dan bawah untuk mengetahui insets,
Kedua:
UIApplication.shared.windows.first{$0.isKeyWindow }?.safeAreaInsets
Yang pertama Anda mengambil insets tampilan, jadi jika ada bilah navigasi akan dipertimbangkan, namun yang kedua Anda mengakses safeAreaInsets jendela sehingga bilah navigasi tidak akan dianggap
safeAreaLayoutGuide Saat tampilan terlihat di layar, panduan ini mencerminkan bagian tampilan yang tidak tercakup oleh bilah navigasi, bilah tab, bilah alat, dan tampilan leluhur lainnya. (Di tvOS, area aman mencerminkan area yang tidak tertutup bezel layar.) Jika tampilan saat ini tidak dipasang dalam hierarki tampilan, atau belum terlihat di layar, tepi panduan tata letak sama dengan tepi tampilan.
Kemudian untuk mendapatkan ketinggian panah merah di tangkapan layar itu:
self.safeAreaLayoutGuide.layoutFrame.size.height
Swift 5, Xcode 11.4
`UIApplication.shared.keyWindow`
Ini akan memberikan peringatan penghentian. '' keyWindow 'sudah tidak digunakan lagi di iOS 13.0: Sebaiknya tidak digunakan untuk aplikasi yang mendukung banyak adegan karena mengembalikan jendela kunci di semua adegan yang terhubung' karena adegan yang terhubung. Saya menggunakan cara ini.
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 Siapa yang punya masalah ketika keyWindow sama dengan nihil . Cukup masukkan kode di atas di viewDidAppear (bukan di viewDidLoad)
Ekstensi 5 Swift
Ini dapat digunakan sebagai Extension dan dipanggil dengan: 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
}
}
Perpanjangan aplikasi UIA adalah opsional, bisa berupa perpanjangan UIView atau apa pun yang disukai, atau mungkin bahkan lebih baik fungsi global.
Pendekatan yang lebih bulat
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
}
}
Bagi Anda yang beralih ke mode lansekap, Anda harus memastikan untuk menggunakan viewSafeAreaInsetsDidChange setelah rotasi untuk mendapatkan nilai terbaru:
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
}
}