我正在试验如何使用UIScrollView。经过多次麻烦,我终于掌握了它。但现在我似乎遇到了另一个障碍。
在这个简单的应用程序中,我有一个滚动视图,为了使它工作,我必须将视图的底部空间设置为滚动视图约束为0,如here所述,它工作正常。我是通过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];
但它似乎不起作用。它在控制台窗口中输出以下消息,我不知道该怎么做。
无法同时满足约束条件。 可能至少下列列表中的一个约束是您不想要的约束。试试这个:(1)看看每个约束并试着找出你不期望的东西; (2)找到添加了不需要的约束或约束的代码并修复它。 (注意:如果您看到您不理解的NSAutoresizingMaskLayoutConstraints,请参阅UIView属性的文档translatesAutoresizingMaskIntoConstraints) ( “” “” )
有人可以告诉我怎么做吗?我还附上了一个演示项目here,以便您可以更好地了解该问题。
更新
首先感谢您的回复。使用答案中提到的方法,我能够使它工作。然而,它的情况略有不同。现在我正在尝试以编程方式将视图加载到viewcontroller。
如果我可以进一步解释。有2个视图控制器。第一个是UITableViewController
,第二个是UIViewController
。在UIScrollView
里面。还有多个UIView
s,其中一些视图的高度超过了屏幕的正常高度。
UITableViewController
显示选项列表。根据用户的选择,该批次中的特定UIView
将被UIViewController
加载到UIScrollView
。
在这种情况下,上述方法不起作用。滚动没有发生。我是否必须做一些不同的事情,因为我单独加载视图?
我上传了一个演示项目here,以便您可以看到它的实际效果。请参阅Email.xib
,然后从表格视图列表中选择电子邮件。
答案 0 :(得分:56)
根据对您的代码的审核,一些评论:
出现视图时,通常无需调整约束。如果您发现自己这样做,通常意味着您没有正确配置故事板(或至少,没有高效率)。你真正需要设置/创建约束的唯一时间是(a)你是以编程方式添加视图(我建议的是更多的工作而不是它的价值);或(b)您需要对约束进行一些运行时调整(参见下面第3点下的第三个项目符号)。
我不是故意的,但你的项目有一堆冗余的代码。 E.g。
您正在为滚动视图设置框架,但这受到约束的约束,因此不执行任何操作(即,当应用约束时,将替换任何手动设置的frame
设置)。通常,在自动布局中,请勿尝试直接更改frame
:编辑约束。但是,无论如何都不需要改变约束,所以重点是没有意义。
您正在设置滚动视图的内容大小,但在自动布局中,它也受(子视图的)约束的约束,因此这是不必要的。
您正在为scrollview设置约束(已经为零),但是您没有将NIB中的视图添加到scrollview中,也打败了那里的任何意图。最初的问题是如何更改滚动视图的底部约束。但对此的底部约束已经为零,所以我认为没有理由再次将其设置为零。
我建议对项目进行更彻底的简化:
通过将您的观点存储在NIB中,您的生活将变得更加艰难。如果你留在故事板世界里会更容易。如果你真的需要,我们可以帮你做NIB的东西,但为什么要让自己的生活变得如此艰难呢?
使用单元格原型来简化表格中单元格的设计。您还可以定义从单元格到下一个场景的segue。这消除了编写任何didSelectRowAtIndexPath
或prepareForSegue
代码的任何需要。显然,如果你有一些东西你需要传递到下一个场景,一定要使用prepareForSegue
,但到目前为止你所提出的并不需要,所以我在我的例子中对它进行了评论。
假设您正在寻找以编程方式更改约束的实际示例,我已设置场景,以便文本视图将根据文本视图中的文本以编程方式更改其高度。与往常一样,在改变IB为我创建的现有约束时,不是迭代约束来找到有问题的约束,我认为为约束设置IBOutlet
更有效,并编辑{直接约束的{1}}属性,这就是我所做的。所以我将视图控制器设置为文本视图的委托,并编写了一个constant
来更新文本视图的高度约束:
textViewDidChange
请注意,我的文本视图有两个高度限制,一个强制性的最小高度约束,以及一个中等优先级约束,我根据文本量更改了上面的优先级约束。重点是它说明了以编程方式更改约束的实际示例。您根本不应该使用scrollview的底部约束,但这显示了您可能想要调整约束的实际示例。
在IB中添加滚动视图时,它将自动获得您需要的所有约束。您可能不希望以编程方式添加约束(至少在没有删除现有底部约束的情况下)。
两种方法可能更简单:
为现有的底部约束创建#pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView
{
self.textViewHeightConstraint.constant = textView.contentSize.height;
[self.scrollView layoutIfNeeded];
}
,例如IBOutlet
。那你就可以做到
scrollViewBottomConstraint
或者最初在IB中创建视图,其中底部约束为0.0,然后您根本无需以编程方式执行任何操作。如果要布置长滚动视图及其子视图,请选择控制器,将其模拟指标从“推断”设置为“自由形式”。然后你可以改变视图的大小,将scrollview的top和bottom约束设置为零,在滚动视图中布置你想要的所有内容,然后在运行时显示视图时,视图将适当调整大小,因为你已经将scrollview的顶部和底部约束定义为0.0,它将被正确调整大小。它在IB中看起来有点奇怪,但它在应用程序运行时就像一个魅力。
如果您决定添加新约束,则可以通过编程方式删除旧的底部约束,或者将旧的底部约束的优先级设置为尽可能低,这样就可以实现新约束(具有更高的约束)优先级将优先,并且优先不应用旧的,低优先级的底部约束。
但你绝对不想只是添加一个新约束。
答案 1 :(得分:21)
可以在视图控制器中创建表示布局约束的插座。只需在界面构建器中选择所需的约束(例如,通过您正在安排的视图的测量窗格上的“选择和编辑”)。然后转到出口窗格并将“新建引用插座”拖到代码文件(.h或.m)中。这会将约束绑定到NSLayoutConstraint
实例,您可以从控制器访问该实例并动态调整(通常通过constant
属性,该属性命名不佳,因为它根本不是常量)。
(请注意,在XCode 6中,您可以双击约束以选择它进行编辑。)
在界面构建器中调整布局时要小心,因为您最终可能会删除约束并且必须将其重新绑定到插座。
答案 2 :(得分:12)
查看控制台信息,我觉得在添加两种相同类型的约束时会产生歧义。
因此,不要创建和添加新约束,而是尝试更新约束数组中已存在的先前约束。
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;
}
}
希望这有帮助
即使Rob的回答也会奏效!
答案 3 :(得分:2)
您可以使用https://github.com/SnapKit/Masonry以编程方式添加约束。
AutoLayout NSLayoutConstraints具有简化,可链接和富有表现力的语法。支持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创建的相同约束
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);
}];
尽力排序;)