在 ViewController 的 loadView 中创建的自动调整视图的 AutoLayout 约束
Posted
技术标签:
【中文标题】在 ViewController 的 loadView 中创建的自动调整视图的 AutoLayout 约束【英文标题】:AutoLayout constraints for a autoresizing view created in ViewController's loadView 【发布时间】:2013-04-28 09:37:03 【问题描述】:我的UIViewController
通过覆盖 loadView 方法来创建它的视图:
- (void)loadView
UIView *view = [[UIView alloc] init];
view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.view = view;
现在我想切换到 AutoLayout 并因此添加一个
view.translatesAutoresizingMaskIntoConstraints = NO;
到 loadView 方法。现在我必须指定之前自动生成的相同约束。我的方法是用
覆盖 updateViewConstraints- (void)updateViewConstraints
if (0 == [[self.view constraints] count])
NSDictionary* views = @@"view" : self.view;
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:0 views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:0 views:views]];
[super updateViewConstraints];
但我得到一个例外,因为我认为这种约束应该与超级视图一起使用:
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal.
那么,正确的 Contraints 应该是什么样子的?
【问题讨论】:
【参考方案1】:你需要在 superview 上设置约束。异常是通过传递“|”引用superview引起的以视觉形式。如果您像下面这样更新代码,它将起作用:
- (void)updateViewConstraints
if (self.view.superview != nil && [[self.view.superview constraints] count] == 0)
NSDictionary* views = @@"view" : self.view;
[self.view.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:0 views:views]];
[self.view.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:0 views:views]];
[super updateViewConstraints];
在实践中,您可能希望检查父视图上的 0 约束以外的其他内容,但这应该会有所帮助。
【讨论】:
【参考方案2】:您不必像 Matt Neuburg 解释的那样在根视图上设置约束 Chapter 19 of his Programming ios 6 book, in section Manual Layout:
我们没有费心给我们的观点
(self.view)
一个合理的框架。这是因为我们依赖其他人来适当地构建视图。在这种情况下,“其他人”是窗口,它响应将其rootViewController
属性设置为视图控制器,方法是将视图控制器的视图适当地框定为根视图,然后将其作为子视图放入窗口。
【讨论】:
【参考方案3】:CEarwood 方法的问题在于,这是一个 ViewController,它的视图不是任何其他视图的子视图,因此调用 self.view.subview 只会导致 nil。请记住,Apple 文档和指南强烈建议 UIViewController 或多或少地占据整个屏幕(除了导航栏或标签栏等)。
Palimondo 的回答基本上是正确的:你的 UIViewController 需要在 loadView 中初始化它的视图,但它不需要指定它的框架或约束,因为它们会自动设置为窗口的框架和约束。如果您自己不实现 loadView,这正是默认情况下所做的。
【讨论】:
有个小错误:你说的是self.view.superview而不是self.view.subview【参考方案4】:我不确定您是否需要为窗口的根视图设置约束。
也就是说,你的约束看起来是正确的,我认为你得到的例外是因为:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:0 views:views]];
使用 |表示视图的超级视图的符号。作为根级视图,它没有超级视图。这样的事情可能会更好:
- (void)loadView
UIView *customView = [[UIView alloc] init];
[self.view addSubview:customView];
NSDictionary* views = @@"customView" : customView;
[customView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|" options:0 metrics:0 views:views]];
[customView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|" options:0 metrics:0 views:views]];
【讨论】:
但我明确不想将视图添加为子视图,因为这样我就会有一个我不需要的未使用视图。 拥有一个额外的、未使用的视图有多重要?我只是在这里问,这是你的问题。您是否尝试过放弃约束?通过 Storyboard 的默认视图控制器有哪些约束? 视图是以编程方式创建的,所以没有来自情节提要。额外的视图会浪费 cpu 时间和内存。 好吧,如果这对您来说很重要,那么听起来您需要跳过根视图的自动布局。 "与窗口的根视图控制器关联的视图根据窗口的特性获取一个框架。" - developer.apple.com/library/ios/#featuredarticles/…以上是关于在 ViewController 的 loadView 中创建的自动调整视图的 AutoLayout 约束的主要内容,如果未能解决你的问题,请参考以下文章
在不同的 ViewController 中切换到新的 ViewController?
在调用 viewController 之前调用 ViewController 方法的问题
如何在使用 Swift 关闭 ViewController 期间将值从 ViewController B 传递给 ViewController A? [复制]
在 SWIFT 语言的 Storyboard 中将值从一个 ViewController 传递到另一个 ViewController