web-dev-qa-db-ja.com

iOS-ビューの上位の制約を見つける?

コードでビューの最上位の制約を見つけようとしています。上部の制約がストーリーボードに追加され、IBOutletを使用したくありません。

次のコードでfirstAttributeの値をログに記録すると、常にNSLayoutAttributeHeightタイプの制約が返されるようです。コードでビューの上位制約を確実に見つける方法はありますか?

NSLayoutConstraint *topConstraint;

for (NSLayoutConstraint *constraint in self.constraints) {
    if (constraint.firstAttribute == NSLayoutAttributeTop) {
        topConstraint = constraint;
        break;
    }
}
19
aryaxt

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;
}
29
JRG-Developer

私は通常、必要な制約のidentifierをIBに設定し、次のようなコードで見つけます(Swift):

if let index = constraints.index(where: { $0.identifier == "checkmarkLeftMargin" }) {
    checkmarkImageViewLeftMargin = constraints[index]
}

または@Tim Vermeulenによる

checkmarkImageViewLeftMargin = constraints.first { $0.identifier == "checkmarkLeftMargin" }
22
SoftDesigner

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
    }
}
3
Igor

@Igor answer に基づいて、ビットitemMatchメソッドを変更して、最初のアイテムまたは2番目のアイテムが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
    }
}
2
Mohammad Eslami

Xcodeのインスペクターで識別子を設定します。それが目的です。あなたはそれに名前を付けます。それで十分でない場合は、IBOutletを作成します。

2
uchuugaka

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) }) } }

0
Serhii Londar