Я не говорю о свойстве frame, потому что из него вы можете получить размер представления только в xib. Я говорю о том, когда размер представления изменяется из-за его ограничений (может быть, после поворота или в ответ на событие). Есть ли способ узнать его текущую ширину и высоту?
Я пробовал перебирать его ограничения в поисках ограничений по ширине и высоте, но это не очень чисто и терпит неудачу, когда есть внутренние ограничения (поскольку я не могу различить эти два). Кроме того, это работает только в том случае, если у них действительно есть ограничения ширины и высоты, чего нет, если они полагаются на другие ограничения для изменения размера.
Почему для меня это так сложно. ARG!
Ответы:
Ответ есть
[view layoutIfNeeded]
.Вот почему:
Вы по-прежнему получаете текущую ширину и высоту представления, проверяя
view.bounds.size.width
иview.bounds.size.height
(или фрейм, что эквивалентно, если вы не играете сview.transform
).Если вам нужна ширина и высота, подразумеваемые вашими существующими ограничениями, ответ - не проверять ограничения вручную, так как это потребует от вас повторной реализации всей логики решения ограничений системы автоматической компоновки, чтобы интерпретировать эти ограничения. ограничения. Вместо этого вам нужно просто попросить автоматический макет обновить этот макет , чтобы он разрешил ограничения и обновил значение view.bounds с правильным решением, а затем вы проверите view.bounds.
Как вы попросите автоматический макет обновить макет? Вызовите,
[view setNeedsLayout]
если хотите, чтобы автоматическая компоновка обновляла компоновку при следующем повороте цикла выполнения.Однако, если вы хотите, чтобы макет обновлялся немедленно, чтобы вы могли сразу же получить доступ к новому значению границ позже в вашей текущей функции или в другой момент до поворота цикла выполнения, вам необходимо вызвать
[view setNeedsLayout]
и[view layoutIfNeeded]
.Вы задали второй вопрос: «как я могу изменить ограничение высоты / ширины, если у меня нет ссылки на него напрямую?».
Если вы создаете ограничение в IB, лучшим решением будет создание IBOutlet в вашем контроллере представления или в вашем представлении, чтобы у вас была прямая ссылка на него. Если вы создали ограничение в коде, вам следует удерживать ссылку во внутреннем слабом свойстве в то время, когда вы его создавали. Если кто-то другой создал ограничение, вам необходимо найти его, изучив свойство view.constraints в представлении и, возможно, всю иерархию представления, и реализовав логику, которая находит критически важный NSLayoutConstraint. Это, вероятно, неправильный путь, поскольку он также фактически требует от вас определения того, какое конкретное ограничение определяет размер границ, когда нет гарантии, что на этот вопрос будет простой ответ. Окончательное значение границ может быть решением очень сложной системы множественных ограничений,
источник
layoutIfNeeded
отлично, и сделает раму доступной сразу. Тем не менее, он также принудительно отрисовывает ограничения для всех представлений в поддеревьях представления, для которого оно вызвано. Если вы, например, программно добавляете представления и вызываете ихlayoutIfNeeded
все в своей рекурсивной процедуре, вы можете обнаружить, что ваша иерархия представлений отображается очень медленно. (Я усвоил это на собственном горьком опыте) Как упоминалось в отличном ответе, setNeedsLayout более эффективен и сделает кадр доступным на следующем проходе макета, что в идеале происходит примерно за 1/60 секунды.initWithCoder
?У меня была аналогичная проблема, когда мне нужно было добавить верхнюю и нижнюю границу к
UITableView
объекту, размер которого изменяется в зависимости от настроек ограничений в файлеUIStoryboard
. Я смог получить доступ к обновленным ограничениям с помощью- (void)viewDidLayoutSubviews
. Это полезно для того, чтобы не создавать подклассы для представления и переопределять его метод компоновки.Без вызова метода из
viewDidLayoutSubview
метода правильно отображается только верхняя граница, так как нижняя граница находится где-то за пределами экрана.источник
[super viewDidLayoutSubviews];
Для тех, кто все еще может сталкиваться с такими проблемами, особенно с TableviewCell.
Просто переопределите метод:
В случае UITableViewCell или UICollectionViewCell создайте подкласс ячейки и переопределите тот же метод:
источник
Пользуйтесь
-(void)viewWillAppear:(BOOL)animated
и звоните[self.view layoutIfNeeded];
- работает Я пробовал.потому что, если вы
-(void)viewDidLayoutSubviews
его используете, он определенно будет работать, но этот метод вызывается каждый раз, когда ваш пользовательский интерфейс требует обновлений / изменений. С которым будет трудно справиться. Программная клавиша - вы используете переменную типа bool, чтобы избежать такого цикла вызовов. лучше использоватьviewWillAppear
. Помните,viewWillAppear
что также будет вызываться, если представление снова загружается (без перераспределения).источник
Рамка еще действительна. В конце концов, представление использует свойство frame, чтобы расположить себя. Он вычисляет этот кадр на основе всех ограничений. Ограничения используются только для начального макета (и каждый раз, когда layoutSubviews вызывается в представлении, например, после поворота). После этого информация о позиции находится в свойстве frame. Или вы видите иначе?
источник