IOS Autolayout - размер кадра не установлен в viewDidLayoutSubviews
Я работаю на клавиатуре для iOS 8, используя Autolayout, чтобы поместить кнопки в представление.
Когда я меняю макет с использованием ограничений, все отображается правильно на экране, но когда я хочу знать размер кадра представления, я не получаю нужный размер.
Например: я нажимаю клавишу, раскладка клавиатуры меняет и компоноет все по моим ограничениям. Затем я хочу знать размер любой кнопки на экране - я делаю это в "viewDidLayoutSubviews" и получаю этот результат в консоли:
2014-10-29 12:27:09.088 Keyboard[2193:60674] view did layout subviews
2014-10-29 12:27:09.088 Keyboard[2193:60674] {{inf, inf}, {0, 0}}
Кнопка имеет правильный размер и правильное положение, но при попытке получить свой кадр размер не установлен.
Где я должен поместить свой код, когда он не работает в viewDidLayoutSubviews?
Я нашел много вопросов о stackoverflow и других веб-сайтах, но ни один из них не затронул мой вопрос.
Ответы
Ответ 1
Я столкнулся с очень похожим вопросом (вопрос с поддержкой) и нашел beeef answer, чтобы указать в правильном направлении. Учитывая, что в документации Apple указано, что вы не вызываете layoutSubviews() напрямую, я вместо этого сделал следующее (где mySubView является прямым подзаголовком self.view):
override func viewDidLayoutSubviews() {
// self.view direct subviews are laid out.
// force my subview to layout its subviews:
self.mySubView.setNeedsLayout()
self.mySubView.layoutIfNeeded()
// here we can get the frame of subviews of mySubView
// and do useful things with that...
}
Просто FYI, в моем случае mySubView - это UIScrollView, и мне нужно получить кадр одного из его подзонов, чтобы я мог установить contentOffset соответственно до появления представления. Я не уверен, что viewDidLayoutSubviews() - лучшее место для этого, но это гарантирует, что mySubView будет выложен.
Ответ 2
Да! Я сам решил эту проблему.
Я не уверен, правильно ли я это понял, но это то, что я думаю:
- viewDidLayoutSubviews вызывается каждый раз при изменении макета
- viewDidLayoutSubviews вызывается, когда прямые субвью моего представления делали макет, но в подзаголовках этого subviews не было макета в этот момент, поэтому вы не можете получить их размер.
Мое решение теперь состояло в том, чтобы вручную вызвать .layoutSubviews() во всех моих представлениях, который содержит все мои кнопки на моей клавиатуре. После этого я получаю размер всех кнопок, которые я хочу.
Пожалуйста, поправьте меня, если я ошибаюсь.
Ответ 3
Я всегда чувствую себя немного грязным при обращении к DispatchQueue.asyncAfter(), но он чувствует себя оправданным в этом случае, поскольку viewDidLayoutSubviews вызывается до того, как все настройки AutoLayout в иерархии представлений произойдут. Я предпочитаю, чтобы он форсировал дополнительную синхронную компоновку.
override func viewDidLayoutSubviews() {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) { [weak self] in
// Updated sub-subview frames can be accessed here
// Note - access self weakly here for the unlikely, but possible, case it was deallocated
}
}