iOS - 查找视图的顶部约束?
Posted
技术标签:
【中文标题】iOS - 查找视图的顶部约束?【英文标题】:iOS - Find top constraint for a view? 【发布时间】:2014-11-09 21:39:35 【问题描述】:我试图在代码中找到视图的顶部约束。 故事板中添加了顶部约束,我不想使用 IBOutlet。
在以下代码中记录 firstAttribute 的值似乎总是返回 NSLayoutAttributeHeight 类型的约束。知道如何在代码中可靠地找到视图的最高约束吗?
NSLayoutConstraint *topConstraint;
for (NSLayoutConstraint *constraint in self.constraints)
if (constraint.firstAttribute == NSLayoutAttributeTop)
topConstraint = constraint;
break;
【问题讨论】:
【参考方案1】:您应该遍历self.superview.constraints
,而不是遍历self.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;
【讨论】:
感谢通过父母的约束进行枚举 您可以通过将 findTopConstraint 更改为使用 UIView 方法constraintsAffectingLayoutForAxis:
返回的数组来使其更准确和更短。这消除了正交轴上的约束。
@uchuugaka Apple 文档中的这个声明让我暂停使用constraintsAffectingLayoutForAxis:
,This method should only be used for debugging constraint-based layout. No application should ship with calls to this method as part of its operation.
AFAIK,但是通过 constraints
数组枚举没有任何问题。
没注意到。很好地找到了文档说明。【参考方案2】:
我通常在 IB 中设置一个所需约束的identifier
,然后在这样的代码中找到它(Swift):
if let index = constraints.index(where: $0.identifier == "checkmarkLeftMargin" )
checkmarkImageViewLeftMargin = constraints[index]
或@Tim Vermeulen
checkmarkImageViewLeftMargin = constraints.first $0.identifier == "checkmarkLeftMargin"
【讨论】:
if let constraint = constraints.filter $0.identifier == "checkmarkLeftMargin" .first
:)
@SeanDev 一旦必要的约束源,循环就会中断。在第一个示例中,所有约束都使用指定的标识符进行搜索。当然,在实际条件下,它不会花费太多时间,但仍然如此。
@aryaxt 有first(where:)
!
如果您在界面生成器中完成所有这些,您还可以设置一个 Outlet。【参考方案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】:基于@Igor answer,我更改了位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
【讨论】:
【参考方案5】:在 Xcode 的检查器中设置标识符。这就是它的用途。你给它命名。 如果这还不够,您可以创建 IBOutlet。
【讨论】:
这并不适用于所有情况。例如,如果您正在开发一个打算供其他开发人员使用/子类化/等的库,您可能不希望他们必须显式地将IBOutlet
设置为顶部约束。跨度>
为什么不呢?如果你不打算这样做,那么他们必须这样做。否则,您使用标识符命名它。但是明确的属性是清晰易懂的。
我不想使用标识符,否则我会使用 IBOUTlet。我希望它能够动态工作
动态意味着创建易于识别的事物。如今,UIKit 和 AppKit 到处都有标识符属性是有原因的。如果没有这个或插座,那么您只能通过查看影响给定视图的特定方向布局的每个约束的属性来猜测。
使用标识符或插座不是动态的。使用代码并通过约束不是猜测工作,看看上面提供的示例非常可靠。使用标识符,您必须记住标识符名称应该是什么是猜测工作。在为具有特定标识符(非动态)的特定案例编写代码时使用标识符【参考方案6】:
我用 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) )
【讨论】:
【参考方案7】:这是一种基于@Igor 方法的单行扩展方法:
extension UIView
func constraint(for layoutAttribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint?
return superview?.constraints.first itemMatch(constraint: $0, layoutAttribute: layoutAttribute)
private func itemMatch(constraint: NSLayoutConstraint, layoutAttribute: NSLayoutConstraint.Attribute) -> 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
[我还制作了方法签名样式以匹配 Swift 3...5 样式,例如:
constraint(for:)
而不是findConstraint(layoutAttribute:)
。
]
【讨论】:
以上是关于iOS - 查找视图的顶部约束?的主要内容,如果未能解决你的问题,请参考以下文章
随着 iOS 7 的视图控制器是全屏的,是不是可以在视图的最顶部设置约束,而不仅仅是导航栏?