以编程方式设置约束
我正在试验如何使用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
将被加载到带有UIScrollView
的UIViewController
。
在这种情况下,上述方法不起作用。 滚动没有发生。 我是否需要单独加载视图才能做一些不同的事情?
我已经在这里上传了一个演示项目,这样你就可以看到它的实际运行。 请参阅Email.xib
并从表格视图列表中select电子邮件 。
根据您的代码审查,一些评论:
-
出现视图时,通常不需要调整约束条件。 如果你发现自己这样做,通常意味着你没有正确configuration你的故事板(或者至less不是有效的)。 唯一一次你真的需要设置/创build约束是(a)你以编程方式添加视图(我build议更多的工作,而不是值得); 或者(b)您需要对约束进行一些运行时调整(参见下面第3点下的第三个项目符号)。
-
我不是故意的,但是你的项目有一堆冗余的代码。 例如
-
您正在设置滚动视图的框架,但这是受限制的,所以什么都不做(即当应用约束时,任何手动设置的
frame
设置将被replace)。 一般来说,在自动布局中,不要直接尝试改变frame
:编辑约束。 但是,不pipe怎样都不需要改变约束,所以这个问题是没有意义的。 -
您正在设置滚动视图的内容大小,但是在自动布局中,这也受到(子视图的)约束的限制,所以这是不必要的。
-
你为scrollview设置了约束(已经是零),但是你并没有将NIB中的视图添加到scrollview中,也没有打破任何意图。 原来的问题是如何改变滚动视图的底部约束。 但底部的约束已经是零,所以我没有理由再次将其设置为零。
-
-
我会build议你的项目更彻底的简化:
-
通过将你的观点存储在NIB中,你使自己的生活变得更加困难。 如果你留在故事板的世界里,这会容易得多。 如果你真的需要,我们可以帮助你做NIB的东西,但为什么要让自己的生活如此艰难?
-
使用单元格原型来促进表格中单元格的devise。 您也可以定义细胞从细胞到下一个场景。 这消除了任何需要编写任何
didSelectRowAtIndexPath
或prepareForSegue
代码。 显然,如果你有什么东西需要传递到下一个场景,通过一切手段使用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不是除去现有的底部约束)。
两种方法可能更简单:
-
为您现有的底部约束创build一个
IBOutlet
,例如scrollViewBottomConstraint
。 那么你可以做self.scrollViewBottomConstraint.constant = 0.0;
-
或者最初在IB中创build你的视图,其底部约束为0.0,然后你不需要以编程方式做任何事情。 如果你想布局一个长的滚动视图和它的子视图,select控制器,将其模拟度量从“推断”设置为“自由forms”。 然后,您可以更改视图的大小,将滚动视图的顶部和底部约束设置为零,在滚动视图内部布置所需的所有内容,然后在运行时显示视图时,视图将适当resize,因为您已经定义了滚动视图的顶部和底部约束为0.0,它将被正确resize。 在IB看起来有些奇怪,但是它在应用程序运行时就像一个魅力。
-
如果你决定增加一个新的约束条件,你可以通过编程来删除旧的底部约束条件,或者将旧的底部约束条件的优先级降低到最低,这样你的新的约束条件(优先级更高)而旧的,低优先级的底部约束将优先不适用。
但是,你绝对不想只添加一个新的约束。
可以创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); }];
尽力而为;)