Как я могу получить текущую ширину и высоту представления при использовании ограничений автоопределения?

Я не говорю о свойстве frame, потому что из этого вы можете получить только размер представления в xib. Я говорю о том, когда представление изменяется из-за его ограничений (возможно, после поворота или в ответ на событие). Есть ли способ получить его текущую ширину и высоту?

Я попытался выполнить итерацию с помощью ограничений, связанных с ограничениями ширины и высоты, но это не очень чистое и не выполняется, когда есть внутренние ограничения (поскольку я не могу различать их). Кроме того, это работает только в том случае, если у них на самом деле есть ограничения по ширине и высоте, которых нет, если они полагаются на другие ограничения для изменения размера.

Почему это так сложно для меня. ARG!

Ответ 1

Ответ [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. Вероятно, это неправильный путь, так как он также эффективно требует, чтобы определить, какое конкретное ограничение определяет размер границ, когда не гарантируется простой ответ на этот вопрос. Конечное значение границ может быть решением очень сложной системы множественных ограничений, с несколькими приоритетами и т.д., Так что ни одно ограничение не является "причиной" конечного значения.

Ответ 2

У меня была аналогичная проблема, когда мне нужно было добавить верхнюю и нижнюю границу к UITableView, которая меняет размеры на основе настроек ограничений в UIStoryboard. Мне удалось получить доступ к обновленным ограничениям с помощью - (void)viewDidLayoutSubviews. Это полезно, так что вам не нужно подклассифицировать представление и переопределить его метод компоновки.

/*** SET TOP AND BOTTOM BORDERS ON TABLE VIEW ***/
- (void)addBorders
{
    CALayer *topBorder           = [CALayer layer];
    topBorder.frame              = CGRectMake(0.0f, self.tableView.frame.origin.y, 320.0f, 0.5f);
    topBorder.backgroundColor    = [UIColor redColor].CGColor;

    CALayer *bottomBorder        = [CALayer layer];
    bottomBorder.frame           = CGRectMake(0.0f, (self.tableView.frame.origin.y + self.tableView.frame.size.height), 320.0f, 0.5f);
    bottomBorder.backgroundColor = [UIColor redColor].CGColor;

    [self.view.layer addSublayer:topBorder];
    [self.view.layer addSublayer:bottomBorder];
}

/*** GET AUTORESIZED FRAME DIMENSIONS ***/
- (void)viewDidLayoutSubviews{
    [self addBorders];
}

Не вызывая метод из метода viewDidLayoutSubview, только верхняя граница рисуется правильно, так как нижняя граница где-то вне экрана.

Ответ 3

Для тех, кто все еще может столкнуться с такими проблемами, особенно с TableviewCell.

Просто переопределите метод:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

Если UITableViewCell или UICollectionViewCell создают подкласс ячейки и переопределяют один и тот же метод:

-(void)layoutSubviews
{
//your code here like drawing a shadow
}

Ответ 4

Рамка по-прежнему действительна. В конце, представление использует свое свойство кадра, чтобы выделиться. Он вычисляет этот фрейм на основе всех ограничений. Ограничения используются только для начальной компоновки (и любое время layoutSubviews вызывается в виде, как после поворота). После этого информация о местоположении находится в свойстве frame. Или вы видите иначе?

Ответ 5

Используйте -(void)viewWillAppear:(BOOL)animated и вызывайте [self.view layoutIfNeeded]; - он работает, я пробовал.

потому что если вы используете -(void)viewDidLayoutSubviews, он будет работать определенно, но этот метод вызывается каждый раз, когда ваш пользовательский интерфейс требует изменений/изменений. Который будет трудно справиться. Программный ключ - вы используете переменную bool, чтобы избежать такого цикла вызовов. лучше использовать viewWillAppear. Помните, что viewWillAppear также вызывается, если просмотр снова загружается (без перераспределения).