Подтвердить что ты не робот

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 и других веб-сайтах, но ни один из них не затронул мой вопрос.

4b9b3361

Ответ 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
    }
}