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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19078278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:50:08  来源:igfitidea点击:

Is there any way to add constraint between a view and the top layout guide in a xib file?

iosxcodeios7xcode5

提问by Henry H Miao

In iOS 7, we can now add a constraint between a view and the top layout guide, which I think is very useful to solve the status bar offset issue in iOS7(especially when there is no navigation bar in the view).

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

In a storyboard file, I can add this kind of constraints easily. Just hold the control key then drag the view to the container, it will show the "Top Space to Top Layout Guide" option.

在故事板文件中,我可以轻松添加这种约束。只需按住控制键,然后将视图拖到容器中,它就会显示“顶部空间到顶部布局指南”选项。

enter image description here

在此处输入图片说明

But when I do the same operation in a xib file, this option disappears.

但是当我在一个 xib 文件中做同样的操作时,这个选项就消失了。

enter image description here

在此处输入图片说明

So, is there any way to add this kind of constraints in xib files? Or do I have to add them with code?

那么,有没有办法在 xib 文件中添加这种约束?还是我必须用代码添加它们?

回答by Neeraj Khede

You should refer the following example, this will definitely help you for your problem. I got this from http://developer.apple.com.

您应该参考以下示例,这肯定会帮助您解决问题。我从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]
];

回答by ananfang

Here is my alternative solution.

这是我的替代解决方案。

Find a UIView as a pivot, set its top layout constraint a fixed vertical space to container's top.

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

Control-Drag this layout constraint as an IBOutlet, such as

Control-Drag 此布局约束为 IBOutlet,例如

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

Finally, just override viewWillLayoutSubviews method of UIViewController like following

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

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

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

All the other views' top constraint are based this pivot view, all done :)

所有其他视图的顶部约束都基于此枢轴视图,全部完成:)

回答by Radu Vlad

From iOS 9 you can also do it more simple with topLayoutGuide's anchors:

从 iOS 9 开始,您还可以使用 topLayoutGuide 更简单地做到这一点anchors

  • Swift 3
  • 斯威夫特 3

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

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

  • ObjC
  • 对象

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

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

回答by keshav vishwkarma

Of course, You can not only add constraint between a view and the top layout guideor bottom layout guideby programmatically but also you can remove and access constraint between a view and the top and bottom layout guidewith the help of KVConstraintExtensionsMasterlibrary.

当然,你不仅可以添加约束视图和之间top layout guidebottom layout guide通过编程方式,也可以将视图和之间移除和存取限制top and bottom layout guide的帮助下KVConstraintExtensionsMaster库。

// 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 ];

回答by Cao Huu Loc

Until now even using XCode 6 I cannot align controls to top layout guide on .xib files. Instead, I am using an alternative way.

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

First, on interface builder, I still align controls to top border of viewcontroler's view.

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

Then, in viewDidLoad method, I replace some constraints so they will align to top layout guide instead of main view:

然后,在 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;
}

Think this is not the best way because we replace objects that we define on interface builder. But it may be an alternative way that we can think about.

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

回答by David Pettigrew

I think the reason they don't show up in the XIB is that there is no knowledge of the view controller hierarchy in that situation, whereas in a story board IB can tell where the guides are from the view controller hierarchy the view is in. I.e If it is contained in a UINavigationController, it can determine that the top layout guide is below the navigation toolbar.

我认为它们没有出现在 XIB 中的原因是在这种情况下不知道视图控制器层次结构,而在故事板中,IB 可以从视图控制器层次结构中分辨出视图所在的指南。即如果它包含在一个 UINavigationController 中,它可以确定顶部布局指南在导航工具栏下方。

回答by f3dm76

Cao Huu Loc's answer with swift 4

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