以编程方式设置约束

我正在试验如何使用UIScrollView。 经过很多麻烦,我终于得到了它的挂钩。 但现在我似乎又遇到了另一个障碍。

在这个简单的应用程序,我有一个滚动视图,为了它的工作,我必须设置视图的底部空间滚动视图约束为0,如这里所述,它工作正常。 我正在通过IB来完成。

现在我遇到了一个场景,我必须通过编程来完成这个部分。 我在viewDidLoad方法中添加了下面的代码。

 NSLayoutConstraint *bottomSpaceConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.scrollView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]; [self.view addConstraint:bottomSpaceConstraint]; 

但似乎没有工作。 它在控制台窗口中输出以下消息,我不知道该怎么做。

无法同时满足约束。 下面列表中的至less一个约束可能是你不想要的。 试试这个:(1)看看每一个约束,试图找出你不期望的; (2)find添加不需要的约束或约束的代码并修复它。 (注意:如果你看到你不明白的NSAutoresizingMaskLayoutConstraints,请参阅UIView属性的文档translatesAutoresizingMaskIntoConstraints)(“”,“”)

有人可以告诉我如何做到这一点? 我还附加了一个演示项目,以便您可以更好地了解这个问题。

更新:

首先谢谢你的回应。 使用答案中提到的方式,我能够得到它的工作。 然而,略有不同的情况下,它不是。 现在我试图以编程方式将视图加载到viewcontroller。

如果我可以进一步解释。 有2个视图控制器。 第一个是UITableViewController ,第二个是UIViewController 。 里面有一个UIScrollView 。 另外还有多个UIView ,其中一些视图的高度超出了屏幕的正常高度。

UITableViewController显示一个选项列表。 根据用户的select,一个特定的UIView将被加载到带有UIScrollViewUIViewController

在这种情况下,上述方法不起作用。 滚动没有发生。 我是否需要单独加载视图才能做一些不同的事情?

我已经在这里上传了一个演示项目,这样你就可以看到它的实际运行。 请参阅Email.xib并从表格视图列表中select电子邮件

根据您的代码审查,一些评论:

  1. 出现视图时,通常不需要调整约束条件。 如果你发现自己这样做,通常意味着你没有正确configuration你的故事板(或者至less不是有效的)。 唯一一次你真的需要设置/创build约束是(a)你以编程方式添加视图(我build议更多的工作,而不是值得); 或者(b)您需要对约束进行一些运行时调整(参见下面第3点下的第三个项目符号)。

  2. 我不是故意的,但是你的项目有一堆冗余的代码。 例如

    • 您正在设置滚动视图的框架,但这是受限制的,所以什么都不做(即当应用约束时,任何手动设置的frame设置将被replace)。 一般来说,在自动布局中,不要直接尝试改变frame :编辑约束。 但是,不pipe怎样都不需要改变约束,所以这个问题是没有意义的。

    • 您正在设置滚动视图的内容大小,但是在自动布局中,这也受到(子视图的)约束的限制,所以这是不必要的。

    • 你为scrollview设置了约束(已经是零),但是你并没有将NIB中的视图添加到scrollview中,也没有打破任何意图。 原来的问题是如何改变滚动视图的底部约束。 但底部的约束已经是零,所以我没有理由再次将其设置为零。

  3. 我会build议你的项目更彻底的简化:

    • 通过将你的观点存储在NIB中,你使自己的生活变得更加困难。 如果你留在故事板的世界里,这会容易得多。 如果你真的需要,我们可以帮助你做NIB的东西,但为什么要让自己的生活如此艰难?

    • 使用单元格原型来促进表格中单元格的devise。 您也可以定义细胞从细胞到下一个场景。 这消除了任何需要编写任何didSelectRowAtIndexPathprepareForSegue代码。 显然,如果你有什么东西需要传递到下一个场景,通过一切手段使用prepareForSegue ,但是迄今为止提供的东西都不需要,所以我已经在我的例子中进行了评论。

    • 假设你正在寻找一个以编程方式改变约束的实际例子,我已经设置了场景,以便文本视图将根据文本视图中的文本以编程方式改变其高度。 与往常一样,不是迭代通过约束来find问题,而是在更改IB创build的现有约束时,我认为为约束设置IBOutlet并编辑约束的constant属性效率更高直接,这就是我所做的。 所以我设置了视图控制器作为文本视图的委托,并编写了一个textViewDidChange来更新文本视图的高度约束:

       #pragma mark - UITextViewDelegate - (void)textViewDidChange:(UITextView *)textView { self.textViewHeightConstraint.constant = textView.contentSize.height; [self.scrollView layoutIfNeeded]; } 

      请注意,我的文本视图有两个高度约束,一个强制性最小高度约束和一个中等优先级约束,根据文本数量进行更改。 重点是它以编程方式说明了改变约束的一个实际例子。 你不应该混淆scrollview的底部约束,但是这是一个真实的例子,你可能想要调整一个约束。


在IB中添加滚动视图时,它将自动获取所有您需要的约束。 您可能不希望以编程方式添加约束(至less不是除去现有的底部约束)。

两种方法可能更简单:

  1. 为您现有的底部约束创build一个IBOutlet ,例如scrollViewBottomConstraint 。 那么你可以做

     self.scrollViewBottomConstraint.constant = 0.0; 
  2. 或者最初在IB中创build你的视图,其底部约束为0.0,然后你不需要以编程方式做任何事情。 如果你想布局一个长的滚动视图和它的子视图,select控制器,将其模拟度量从“推断”设置为“自由forms”。 然后,您可以更改视图的大小,将滚动视图的顶部和底部约束设置为零,在滚动视图内部布置所需的所有内容,然后在运行时显示视图时,视图将适当resize,因为您已经定义了滚动视图的顶部和底部约束为0.0,它将被正确resize。 在IB看起来有些奇怪,但是它在应用程序运行时就像一个魅力。

  3. 如果你决定增加一个新的约束条件,你可以通过编程来删除旧的底部约束条件,或者将旧的底部约束条件的优先级降低到最低,这样你的新的约束条件(优先级更高)而旧的,低优先级的底部约束将优先不适用。

但是,你绝对不想只添加一个新的约束。

可以创build出口代表视图控制器中的布局约束。 只需在界面编辑器中select你想要的约束(例如,通过你正在安排的视图的测量面板上的“select并编辑”)。 然后转到sockets面板,将“新引用sockets”拖到您的代码文件(.h或.m)中。 这将约束绑定到一个NSLayoutConstraint实例,您可以从您的控制器访问并dynamic地dynamic调整(通常通过constant属性,这是不好的命名,因为它不是一个常数)。

在这里输入图像说明

(请注意,在XCode 6中,您可以双击约束来select它进行编辑。)

在这里输入图像说明

调整界面构build器中的布局时要小心,因为您最终可能会删除该约束,必须重新将其绑定到sockets。

看着控制台的信息,我觉得你添加两个相同types的约束时会产生歧义。

因此,不要创build和添加新的约束,而是尝试更新约束数组中已有的约束。

 for(NSLayoutConstraint *constraint in self.view.constraints) { if(constraint.firstAttribute == NSLayoutAttributeBottom && constraint.secondAttribute == NSLayoutAttributeBottom && constraint.firstItem == self.view && constraint.secondItem == self.scrollView) { constraint.constant = 0.0; } } 

希望这可以帮助

即使罗布的答案将工作!

您可以使用https://github.com/SnapKit/Masonry以编程方式添加约束。

AutoLayout NSLayoutConstraints具有简化,可链接和expression式语法的强大function。 支持iOS和OSX自动布局。

 UIView *superview = self.view; UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; view1.backgroundColor = [UIColor greenColor]; [superview addSubview:view1]; UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); [superview addConstraints:@[ //view1 constraints [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:padding.top], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeft multiplier:1.0 constant:padding.left], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-padding.bottom], [NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeRight multiplier:1 constant:-padding.right],]]; 

只有几行

下面是使用MASConstraintMaker创build的相同约束

 UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler make.left.equalTo(superview.mas_left).with.offset(padding.left); make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom); make.right.equalTo(superview.mas_right).with.offset(-padding.right); }]; 

甚至更短

 [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(superview).with.insets(padding); }]; 

尽力而为;)