我正在更新我的应用程序以适应iPhone X.除了一个,所有视图现在都可以正常工作。我有一个视图控制器,提供覆盖整个屏幕的自定义UIView。在我使用UIScreen.main.bounds
在所有布局完成之前找出视图的大小之前(我需要它来为collectionView放置正确的itemSize)。我想现在我可以做点什么了
UIScreen.main.bounds.size.height - safeAreaInsets.bottom
以获得正确的可用大小。问题是,safeAreaInsets在iPhone X(模拟器)上尝试返回(0,0,0,0)。有任何想法吗?在其他视图中,我得到了safeAreaInsets的正确数字。
谢谢!
答案 0 :(得分:36)
我最近有一个类似的问题,一旦触发viewDidLoad,安全区域insets将返回(0,0,0,0)。它们似乎比视图加载的其余部分稍晚设置。
我通过覆盖 viewSafeAreaInsetsDidChange 来完成它,并在其中执行我的布局:
override func viewSafeAreaInsetsDidChange() {
// ... your layout code here
}
答案 1 :(得分:34)
我已经找到了解决方案:我正在视图的init
中执行所有实现。 safeAreaInsets在layoutSubviews()
答案 2 :(得分:17)
我有一个视图,它是另一个视图中的子视图。 我发现我无法正确获取safeAreaInsets,它总是在iPhoneX上的那个视图中返回0,即使我把它放在layoutSubviews中。 最后的解决方案是我使用UIScreen扩展来检测safeAreaInsets,它可以像魅力一样工作。
extension UIScreen {
func widthOfSafeArea() -> CGFloat {
guard let rootView = UIApplication.shared.keyWindow else { return 0 }
if #available(iOS 11.0, *) {
let leftInset = rootView.safeAreaInsets.left
let rightInset = rootView.safeAreaInsets.right
return rootView.bounds.width - leftInset - rightInset
} else {
return rootView.bounds.width
}
}
func heightOfSafeArea() -> CGFloat {
guard let rootView = UIApplication.shared.keyWindow else { return 0 }
if #available(iOS 11.0, *) {
let topInset = rootView.safeAreaInsets.top
let bottomInset = rootView.safeAreaInsets.bottom
return rootView.bounds.height - topInset - bottomInset
} else {
return rootView.bounds.height
}
}
}
答案 3 :(得分:17)
我也遇到了这个问题,试图提升视图以便为iPhone X上的键盘让路。主视图的safeAreaInsets始终为0,即使我知道子视图已经布局在这一点,因为屏幕已被绘制。我发现,如上所述,是找到keyWindow并检查其安全区域插入。
的OBJ-C:
CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;
夫特:
let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom
然后,您可以根据需要使用此值调整约束或查看框架。
答案 4 :(得分:5)
Swift iOS 11,12,13 +
var insets : UIEdgeInsets = .zero
override func viewDidLoad() {
super.viewDidLoad()
insets = UIApplication.shared.delegate?.window??.safeAreaInsets ?? .zero
//Or you can use this
insets = self.view.safeAreaInsets
}
答案 5 :(得分:3)
在我的情况下,我在viewDidLoad()中添加了一个UICollectionView
collectionView = UICollectionView(frame: view.safeAreaLayoutGuide.layoutFrame, collectionViewLayout: createCompositionalLayout())
不幸的是,现阶段safeAreaLayoutGuide仍为零。
我通过添加以下内容解决了该问题:
override func viewDidLayoutSubviews() {
collectionView.frame = view.safeAreaLayoutGuide.layoutFrame
}
答案 6 :(得分:2)
容器视图控制器的viewDidAppear(_ :)方法,它扩展了其嵌入式子视图控制器的安全区域,以便考虑其中的视图。
在此方法中进行修改,因为在将视图添加到视图层次结构之前,视图的安全区域insets不准确。
override func viewDidAppear(_ animated: Bool) {
if (@available(iOS 11, *)) {
var newSafeArea = view.safeAreaInsets
// Adjust the safe area to accommodate
// the width of the side view.
if let sideViewWidth = sideView?.bounds.size.width {
newSafeArea.right += sideViewWidth
}
// Adjust the safe area to accommodate
// the height of the bottom view.
if let bottomViewHeight = bottomView?.bounds.size.height {
newSafeArea.bottom += bottomViewHeight
}
// Adjust the safe area insets of the
// embedded child view controller.
let child = self.childViewControllers[0]
child.additionalSafeAreaInsets = newSafeArea
}
}
答案 7 :(得分:2)
我遇到了同样的问题。在我的情况下,在调用view.layoutIfNeeded()
后,我插入的视图将正确调整大小。此后设置了view.safeAreaInsets
,但只有top
值是正确的。底部值仍为0
(在iPhone X上)。
在尝试确定safeAreaInsets
设置正确的时候,我已经在视图的safeAreaInsetsDidChange()
方法中添加了一个断点。这被多次调用,但只有当我在回溯中看到CALayer.layoutSublayers()
时,才能正确设置值。
所以我已经view.layoutIfNeeded()
的对手CALayer
替换了view.layer.layoutIfNeeded()
,这导致safeAreaInsets
立即正确设置,从而解决了我的问题。
<强> TL; DR 强>
替换
view.layoutIfNeeded()
通过
view.layer.layoutIfNeeded()
答案 8 :(得分:2)
我尝试在视图控制器中使用“ self.view.safeAreaInset”。首先,当它在控制器的生命周期方法“ viewDidLoad”中使用它时,它是一个NSInsetZero,然后从网上搜索它并获得正确的答案,日志如下:
ViewController loadView() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewDidLoad() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewWillAppear() SafeAreaInsets :UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
ViewController viewDidLayoutSubviews() SafeAreaInsets :UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
ViewController viewDidAppear() SafeAreaInsets :UIEdgeInsets(top: 44.0, left: 0.0, bottom: 34.0, right: 0.0)
因此您可以选择需要使用safeAreaInset的正确方法并使用它!
答案 9 :(得分:0)
[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero
答案 10 :(得分:0)
只需尝试self.view.safeAreaInsets
而不是UIApplication.shared.keyWindow?.safeAreaInsets
通过应用程序keyWindow请求时,安全区域插图似乎无法在iOS 11.x.x设备上填充。
答案 11 :(得分:0)
在layoutSubviews或viewDidLayoutSubviews之前,不能保证视图布局。在使用这些生命周期方法之前,切勿依赖大小。如果这样做,您将得到不一致的结果。
答案 12 :(得分:0)
要计算安全区域safeAreaInsets,请尝试在viewWIllAppear()中获取它,因为在didLoad()中尚未形成视图。 您将在willAppear中获得正确的插图!
答案 13 :(得分:-1)
如果您使用自动版式,还可以选择将底部约束保持在view.safeAreaLayoutGuide.bottomAnchor
上!
这样,您的布局将始终保持最新状态,而无需观察更改。