有没有办法在xib文件中的视图和顶部布局指南之间添加约束?

时间:2013-09-29 12:54:56

标签: ios xcode ios7 xcode5

在iOS 7中,我们现在可以在视图和顶部布局指南之间添加约束,我认为这对于解决iOS7中的状态栏偏移问题非常有用(特别是当视图中没有导航栏时)。

在故事板文件中,我可以轻松添加这种约束。只需按住控制键,然后将视图拖动到容器,它将显示“Top Space to Top Layout Guide”选项。

enter image description here

但是当我在xib文件中执行相同的操作时,此选项会消失。

enter image description here

那么,有没有办法在xib文件中添加这种约束?或者我是否必须添加代码?

7 个答案:

答案 0 :(得分:78)

您应该参考以下示例,这肯定会帮助您解决问题。我是从http://developer.apple.com得到的。

[button setTranslatesAutoresizingMaskIntoConstraints: NO];
id topGuide = myViewController.topLayoutGuide;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (button, topGuide);

[myViewController.view addConstraints:
    [NSLayoutConstraint constraintsWithVisualFormat: @"V:[topGuide]-20-[button]"
    options: 0
    metrics: nil
    views: viewsDictionary]
];

答案 1 :(得分:14)

这是我的替代解决方案。

将UIView作为一个支点,将其顶部布局约束设置为容器顶部的固定垂直空间。

控制 - 将此布局约束拖动为IBOutlet,例如

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

最后,只需覆盖UIViewController的viewWillLayoutSubviews方法,如下面的

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT;
}

所有其他观点'顶部约束基于此数据透视视图,全部完成:)

答案 2 :(得分:9)

从iOS 9开始,您还可以使用topLayoutGuide anchors更简单:

  • Swift 3

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true

  • ObjC

[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;

答案 3 :(得分:6)

直到现在,即使使用XCode 6,我也无法将控件与.xib文件的顶部布局指南对齐。相反,我正在使用另一种方式。

首先,在界面构建器上,我仍然将控件对齐到viewcontroler视图的顶部边框。

然后,在viewDidLoad方法中,我替换了一些约束,因此它们将与顶部布局指南而不是主视图对齐:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSArray *constraints = self.view.constraints;
    for (NSLayoutConstraint *constraint in constraints) {
        if ( (constraint.firstItem == self.view) && (constraint.firstAttribute == NSLayoutAttributeTop) ) {
            NSLayoutConstraint *newConstraint = [self constraint:constraint replaceFirstItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
            [self.view removeConstraint:constraint];
            [self.view addConstraint:newConstraint];
        } else if ( (constraint.secondItem == self.view) && (constraint.secondAttribute == NSLayoutAttributeTop) ) {
            NSLayoutConstraint *newConstraint = [self constraint:constraint replaceSecondItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
            [self.view removeConstraint:constraint];
            [self.view addConstraint:newConstraint];
        }
    }
}

- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceFirstItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
    UILayoutPriority priority = constraint.priority;
    NSLayoutRelation relation = constraint.relation;
    id secondItem = constraint.secondItem;
    NSLayoutAttribute secondAttribute = constraint.secondAttribute;
    CGFloat multiplier = constraint.multiplier;
    CGFloat constant = constraint.constant;

    NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:newItem attribute:newAttribute relatedBy:relation toItem:secondItem attribute:secondAttribute multiplier:multiplier constant:constant];
    newConstraint.priority = priority;
    return newConstraint;
}

- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceSecondItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
    UILayoutPriority priority = constraint.priority;
    id firstItem = constraint.firstItem;
    NSLayoutAttribute firstAttribute = constraint.firstAttribute;
    NSLayoutRelation relation = constraint.relation;
    CGFloat multiplier = constraint.multiplier;
    CGFloat constant = constraint.constant;

    NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:firstItem attribute:firstAttribute relatedBy:relation toItem:newItem attribute:newAttribute multiplier:multiplier constant:constant];
    newConstraint.priority = priority;
    return newConstraint;
}

认为这不是最好的方法,因为我们替换了我们在界面构建器上定义的对象。但它可能是我们可以考虑的另一种方式。

答案 4 :(得分:6)

当然,您不仅可以通过编程方式在视图与bottom layout guidetop and bottom layout guide之间添加约束,还可以删除和访问视图与// create containerView UIView *containerView = [UIView prepareNewViewForAutoLayout]; [containerView setBackgroundColor:[UIColor brownColor]]; [self.view addSubview:containerView]; // To add Top and Bottom Layout Guide constraint of containerView [self applyTopLayoutGuideConstraintToView:containerView withPadding:0]; [self applyBottomLayoutGuideConstraintToView:containerView withPadding:50]; // To access top Layout Guide Constraint and update it's constant value. NSLayoutConstraint *topLayoutGuideConstraint = [self accessAppliedTopLayoutGuideConstraintFromView:containerView]; topLayoutGuideConstraint.constant = 50; // To access bottom Layout Guide Constraint and update it's constant value with animation NSLayoutConstraint *bottomLayoutGuideConstraint = [self accessAppliedBottomLayoutGuideConstraintFromView:containerView]; bottomLayoutGuideConstraint.constant = 80; [self.view updateModifyConstraintsWithAnimation:NULL]; // call this for animation // To remove Top and Bottom Layout Guide constraint of containerView [self removeAppliedTopLayoutGuideConstraintFromView:containerView]; [self removeAppliedBottomLayoutGuideConstraintFromView:containerView ]; 之间的约束。 KVConstraintExtensionsMaster图书馆的帮助。

{{1}}

答案 5 :(得分:5)

我认为它们没有出现在XIB中的原因是在那种情况下不了解视图控制器层次结构,而在故事板中,IB可以从视图控制器层次结构中看出指南的位置如果它包含在UINavigationController中,它可以确定顶部布局指南位于导航工具栏下方。

答案 6 :(得分:0)

Cao Huu Loc用swift 4答案

extension NSLayoutConstraint {

    func constraintReplacing(firstItemWith newFirstItem: UILayoutSupport, withAttribute newFirstAttribute: NSLayoutAttribute) -> NSLayoutConstraint {
        return NSLayoutConstraint(item: newFirstItem, attribute: newFirstAttribute, relatedBy: relation, toItem: secondItem, attribute: secondAttribute, multiplier: multiplier, constant: constant)
    }

    func constraintReplacing(secondItemWith newSecondItem: UILayoutSupport, withAttribute newSecondAttribute: NSLayoutAttribute) -> NSLayoutConstraint {
        return NSLayoutConstraint(item: firstItem as Any, attribute: firstAttribute, relatedBy: relation, toItem: newSecondItem, attribute: newSecondAttribute, multiplier: multiplier, constant: constant)
    }
}

class YourViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        for constraint in view.constraints {
            if constraint.firstItem === view && constraint.firstAttribute == .top {
                let newConstraint = constraint.constraintReplacing(firstItemWith: topLayoutGuide, withAttribute: .bottom)
                view.removeConstraint(constraint)
                view.addConstraint(newConstraint)
            }
            if constraint.secondItem === view && constraint.secondAttribute == .top {
                let newConstraint = constraint.constraintReplacing(secondItemWith: topLayoutGuide, withAttribute: .bottom)
                view.removeConstraint(constraint)
                view.addConstraint(newConstraint)
            }
        }
    }
}