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


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

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

Почему это так трудно для меня. АРГ!

5 92

5 ответов:

ответ [view layoutIfNeeded].

вот почему:

вы все еще получаете текущую ширину и высоту представления, проверяя view.bounds.size.width и view.bounds.size.height (или кадр, который эквивалентен, если вы не играете с view.transform).

если вы хотите, чтобы ширина и высота подразумевались вашими существующими ограничениями, ответ заключается не в том, чтобы проверять ограничения вручную, так как это потребует от вас повторной реализации всей логики решения ограничений автоматического макета система. Вместо этого, что вы должны сделать, это просто попросите auto layout обновить этот макет, так что он решает ограничения и обновляет значение представления.границы с правильным решением, а затем вы проверяете представление.границы.

как вы просите auto layout обновить макет? Звоните [view setNeedsLayout] если вы хотите, чтобы auto layout обновил макет на следующем витке цикла выполнения.

, если вы хотите, чтобы обновить макет немедленно, так что вы можете немедленно получите доступ к новому значению границ позже в вашей текущей функции, или в другой момент до поворота цикла выполнения, то вам нужно вызвать [view setNeedsLayout] и [view layoutIfNeeded].

вы задали второй вопрос: "как я могу изменить высоту/ограничение ширины, если у меня нет ссылки на него напрямую?".

если вы создаете ограничение в IB, лучшим решением является создание IBOutlet в вашем контроллере представления или в вашем представлении, чтобы у вас была прямая ссылка на него. Если вы создали ограничение в коде, затем вы должны удерживать ссылку во внутреннем слабом свойстве в то время, когда вы его создали. Если кто-то другой создал ограничение, то вам нужно найти его, изучив изучение представления.свойство constraints для представления и, возможно, всей иерархии представлений и реализующей логики, которая находит критический NSLayoutConstraint. Это, вероятно, неправильный путь, так как он также эффективно требует, чтобы вы определили, какое конкретное ограничение определил размер границ, когда не гарантируется простой ответ на этот вопрос. Конечное значение границ может быть решением очень сложной системы множественных ограничений, с несколькими приоритетами и т. д., так что ни одно ограничение не является "причиной" конечного значения.

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

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

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

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

в случае UITableViewCell или UICollectionViewCell создать подкласс ячейки и переопределить тот же метод:

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

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

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

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