我正在尝试在代码中找到视图的顶部约束。顶部约束是在情节提要中添加的,我不想使用 IBOutlet。
在下面的代码中记录第一个属性的值似乎总是返回 NSLayoutAttributeHeight 类型的约束。知道如何在代码中可靠地找到视图的顶部约束吗?
NSLayoutConstraint *topConstraint;
for (NSLayoutConstraint *constraint in self.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeTop) {
topConstraint = constraint;
break;
}
}
与其遍历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;
}
我通常在 IB 中设置一个必需约束的identifier
,然后在代码中找到它,如下所示 (Swift(:
if let index = constraints.index(where: { $0.identifier == "checkmarkLeftMargin" }) {
checkmarkImageViewLeftMargin = constraints[index]
}
或 @Tim 维穆伦
checkmarkImageViewLeftMargin = constraints.first { $0.identifier == "checkmarkLeftMargin" }
基于@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
}
}
使用 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
}
}
在 Xcode 的检查器中设定标识符。这就是它的用途。你的名字。如果这还不够,您可以创建IBOutlet。
我在 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) })
}
}
下面是基于 @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:)
.]
func topConstraint() -> NSLayoutConstraint? {
return superview?.constraints.first {$0.firstAttribute == .top}
}