SafeAreaInsets в UIView - 0 на iPhone X

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

Спасибо!

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

        }

    }

}

Ответ 4

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

Obj-C:

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

Swift:

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

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

Ответ 5

метод 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
  } 
}

Ответ 6

Я столкнулся с той же проблемой. В моем случае вид, который я вставляю, будет правильно задан после вызова 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()

Ответ 7

одна возможность, вы можете использовать [UIApplication sharedApplication].keyWindow.safeAreaInsets to solove

Ответ 8

[UIApplication sharedApplication].keyWindow.safeAreaInsets return none zero

Ответ 9

Просто попробуйте self.view.safeAreaInsets вместо UIApplication.shared.keyWindow?.safeAreaInsets Кажется, что вставки безопасной области не заполняются на устройствах iOS 11.xx при запросе через keyWindow приложения.

Ответ 10

У вас также есть опция, если вы используете автоматическую компоновку, чтобы придерживаться нижнего ограничения для просмотра. view.safeAreaLayoutGuide.bottomAnchor ! Ваш макет будет постоянно обновляться без необходимости наблюдать за изменениями.