safeAreaInsets в UIView-0 на iPhone X

Я обновляю свое приложение, чтобы адаптировать его для iPhone X. Все представления теперь работают нормально, кроме одного. У меня есть контроллер вида, который представляет пользовательский UIView, который охватывает весь экран. Прежде чем я использовал UIScreen.main.bounds чтобы узнать размер представления до того, как был сделан весь макет (он нужен мне для размещения правильного itemSize для collectionView). Я думал, что теперь смогу сделать что-то вроде UIScreen.main.bounds.size.height - safeAreaInsets.bottom чтобы получить правильный полезный размер. Проблема в том, что safeAreaInsets возвращает (0,0,0,0), пытаясь на iPhone X (Тренажер.) Есть идеи? В других представлениях я получаю правильные номера для safeAreaInsets.

спасибо!

6 ответов


Я уже придумал решение: я делал всю реализацию в init представления. safeAreaInsets имеет правильный размер в layoutSubviews()


У меня есть представление, которое является подвидом внутри другого представления. Я обнаружил, что не могу получить safeAreaInsets правильно, он всегда возвращает 0, в этом представлении на iPhoneX, даже если я помещаю его в 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

        }

    }

}

недавно у меня была аналогичная проблема, когда вставки безопасной области возвращаются (0, 0, 0, 0), как только запускается viewDidLoad. Кажется, что они установлены немного позже, чем остальная часть загрузки представления.

Я обошел его, переопределив viewSafeAreaInsetsDidChange и делать мой макет вместо этого:

override func viewSafeAreaInsetsDidChange() {
 // ... your layout code here
} 

я столкнулся с этой проблемой, пытаясь переместить представления, чтобы освободить место для клавиатуры на iPhone X. safeAreaInsets основного представления всегда равны 0, хотя я знаю, что подвиды были выложены в этот момент, когда экран был нарисован. Работа вокруг я нашел, как и упоминалось выше, чтобы получить keyWindow и проверить его безопасные области вставки вместо этого.

Obj-C:

CGFloat bottomInset = [UIApplication sharedApplication].keyWindow.safeAreaInsets.bottom;

Свифт:

let bottomInset = UIApplication.shared.keyWindow?.safeAreaInsets.bottom

затем вы можете использовать это значение для регулировки ограничения или рамки вида по мере необходимости.


я столкнулся с той же проблемой. В моем случае представление, которое я вставляю, будет правильно определено после вызова view.layoutIfNeeded(). The view.safeAreaInsets был установлен после этого, но только top значение было правильным. Нижнее значение по-прежнему 0 (это на iPhone X).

при попытке выяснить, в какой момент safeAreaInsets установлены правильно, я добавил точку останова в представлении safeAreaInsetsDidChange() метод. Это было несколько раз, но только когда я увидел CALayer.layoutSublayers() в backtrace значение было установлено правильно.

Итак, Я заменил view.layoutIfNeeded() на CALayerс контрагентом view.layer.layoutIfNeeded(), что привело к safeAreaInsets чтобы быть установлен правильно сразу, тем самым решая мою проблему.

TL; DR

заменить

view.layoutIfNeeded()

by

view.layer.layoutIfNeeded()

метод viewDidAppear (_:) контроллера представления контейнера, который расширяет безопасную область встроенного контроллера дочернего представления для учета представлений .

внесите изменения в этот метод, потому что вставки безопасной области для представления не точны, пока представление не будет добавлено в иерархию представлений.

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
  } 
}