IOS - найти верхнее ограничение для представления?
Я пытаюсь найти верхнее ограничение представления в коде.
Верхнее ограничение добавляется в раскадровку, и я не хочу использовать IBOutlet.
Запись значения firstAttribute в следующем коде, похоже, всегда возвращает ограничение типа NSLayoutAttributeHeight. Любая идея, как я мог бы надежно найти верхнее ограничение представления в коде?
NSLayoutConstraint *topConstraint;
for (NSLayoutConstraint *constraint in self.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeTop) {
topConstraint = constraint;
break;
}
}
Ответы
Ответ 1
Вместо повторения с помощью self.constraints
вам необходимо выполнить итерацию через self.superview.constraints
.
self.constraints
содержат только ограничения, связанные только с представлением (например, ограничения высоты и ширины).
Вот пример кода, который может выглядеть так:
- (void)awakeFromNib
{
[super awakeFromNib];
if (!self.topConstraint) {
[self findTopConstraint];
}
}
- (void)findTopConstraint
{
for (NSLayoutConstraint *constraint in self.superview.constraints) {
if ([self isTopConstraint:constraint]) {
self.topConstraint = constraint;
break;
}
}
}
- (BOOL)isTopConstraint:(NSLayoutConstraint *)constraint
{
return [self firstItemMatchesTopConstraint:constraint] ||
[self secondItemMatchesTopConstraint:constraint];
}
- (BOOL)firstItemMatchesTopConstraint:(NSLayoutConstraint *)constraint
{
return constraint.firstItem == self && constraint.firstAttribute == NSLayoutAttributeTop;
}
- (BOOL)secondItemMatchesTopConstraint:(NSLayoutConstraint *)constraint
{
return constraint.secondItem == self && constraint.secondAttribute == NSLayoutAttributeTop;
}
Ответ 2
Обычно я устанавливаю identifier
требуемого ограничения в IB, а затем нахожу его в коде, подобном этому (Swift):
if let index = constraints.index(where: { $0.identifier == "checkmarkLeftMargin" }) {
checkmarkImageViewLeftMargin = constraints[index]
}
ИЛИ by @Tim Vermeulen
checkmarkImageViewLeftMargin = constraints.first { $0.identifier == "checkmarkLeftMargin" }
Ответ 3
Использование swift и расширения UIView
extension UIView {
func findConstraint(layoutAttribute: NSLayoutAttribute) -> NSLayoutConstraint? {
if let constraints = superview?.constraints {
for constraint in constraints where itemMatch(constraint: constraint, layoutAttribute: layoutAttribute) {
return constraint
}
}
return nil
}
func itemMatch(constraint: NSLayoutConstraint, layoutAttribute: NSLayoutAttribute) -> Bool {
if let firstItem = constraint.firstItem as? UIView, let secondItem = constraint.secondItem as? UIView {
let firstItemMatch = firstItem == self && constraint.firstAttribute == layoutAttribute
let secondItemMatch = secondItem == self && constraint.secondAttribute == layoutAttribute
return firstItemMatch || secondItemMatch
}
return false
}
}
Ответ 4
Задайте идентификатор в инспекторе в Xcode. Это для чего. Вы называете это.
Если этого недостаточно, вы создаете IBOutlet.
Ответ 5
Я пишу небольшое расширение в Swift:
extension UIButton { var topConstraints: [NSLayoutConstraint]? { return self.constraints.filter( { ($0.firstItem as? UIButton == self && $0.firstAttribute ==.top) || ($0.secondItem as? UIButton == self && $0.secondAttribute ==.top) }) } }
Ответ 6
Основываясь на ответе @Igor, я изменил битовый метод itemMatch, чтобы учитывать, когда первый элемент или второй элемент не является UIView. Например, при ограничении вершины UIView к вершине безопасной области.
extension UIView {
func findConstraint(layoutAttribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint? {
if let constraints = superview?.constraints {
for constraint in constraints where itemMatch(constraint: constraint, layoutAttribute: layoutAttribute) {
return constraint
}
}
return nil
}
func itemMatch(constraint: NSLayoutConstraint, layoutAttribute: NSLayoutConstraint.Attribute) -> Bool {
let firstItemMatch = constraint.firstItem as? UIView == self && constraint.firstAttribute == layoutAttribute
let secondItemMatch = constraint.secondItem as? UIView == self && constraint.secondAttribute == layoutAttribute
return firstItemMatch || secondItemMatch
}
}