我能否在运行时禁用特定子视图的自动布局?

110

我有一个视图需要通过编程方式来操作它的框架 - 它是一种文档视图,可以自动包裹其内容,然后通过操作框架原点在父视图中滚动和缩放。 在运行时,自动布局会与此相冲突。

完全禁用自动布局似乎有些过于严厉,因为它可能合理地用于处理其他视图的布局。 看起来我想要的是某种“空约束”。

14个回答

171
我曾经遇到过同样的问题,但现在已经解决了。
是的,在运行时,你可以为特定的UIView禁用自动布局,而不是像Xcode 4.3及更高版本中默认设置的那样禁用整个xib或storyboard。
在设置子视图的框架之前,将translatesAutoresizingMaskIntoConstraints设置为YES
self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);

2
这似乎对于一些具有大量视图的更复杂情况来说有点过度了。对于像这样简单的东西,这还可以。 - esh
2
@DinhNhat 我澄清了答案。不需要删除和重新添加子视图。 - Leandros
或在Swift中 self.exampleView.setTranslatesAutoresizingMaskIntoConstraints(true) - TimWhiting
5
警告显示:“无法同时满足约束条件。” - NSPratik
1
你救了我的一天... translatesAutoresizingMaskIntoConstraints ... 谁会发明这样的属性 摇头 - Tintenklecks
显示剩余3条评论

50

我曾经遇到过类似的问题,即Autolayout在运行时覆盖了我的一些框架设置(我有一个动态视图,在某些情况下会推送一个新的视图控制器......推送然后按返回按钮会重置初始视图)。

我通过将我的操作代码放在视图控制器的viewDidLayoutSubviews中来解决这个问题。这似乎是在调用任何约束mojo之后调用的,但在viewDidAppear之前调用,因此用户不会察觉到。


1
不适用于self.navigationItem.titleView。仍然无法遵守框架更改。 - Henrik Erlandsson
1
如果您想要修改标题视图的框架,我建议将其放在容器视图中,并将容器视图作为navigationItem的自定义视图添加。 - jmstone617
2
这个方法对我也起作用了。在发现这个解决方法之前,我已经浪费了2小时22分钟的时间在试错中。 - TMc
谢谢,伙计。我忙了两天才解决了这个问题,现在它终于正常工作了! - apostolov

30

也许只需将 translatesAutoresizingMaskIntoConstraints 设置为 YES(而不添加其他影响该视图的约束条件),就可以在不与自动布局系统冲突的情况下设置框架。


17

iOS 8 中,可以将 NSLayoutConstraint 设置为活动或非活动状态。因此,如果我使用界面生成器,则可以将所有约束添加到 OutletCollection,然后使用以下方法激活或停用:

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

我在这里使用的特定应用程序是在纵向和横向模式下具有不同的约束条件,并根据设备的旋转来激活/停用。这意味着我可以在界面构建器中为两种方向创建一些复杂的布局更改,仍然可以使用自动布局而不需要冗长的自动布局代码。
或者您可以使用removeConstraints和addConstraints来激活/停用。

抱歉打扰了这么老的问题,但我可以问一下您是如何在不同布局中添加布局约束的吗?我似乎找不到在界面构建器中启用/禁用约束的选项。或者您只是为两个布局添加了约束,并忽略了界面构建器对无效(覆盖)约束的抱怨? - Malte
你可以使用尺寸类来实现:https://developer.apple.com/library/ios/recipes/xcode_help-IB_adaptive_sizes/chapters/SelectingASizeClass.html#//apple_ref/doc/uid/TP40014436-CH7-SW1,但我不能这样做,因为我还要支持iOS 7,而尺寸类并不完全支持iOS 7。我通过降低冲突约束的优先级来解决问题。虽然不是最理想的方法,但它可以避免警告。我想这就是我当时的做法... - bandejapaisa

10

我不知道这是否会对其他人有所帮助,但我写了一个分类来方便自己,因为我经常需要这样做。

UIView+DisableAutolayoutTemporarily.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView+DisableAutolayoutTemporarily.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

我是这样使用它的:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {    [view setFrame:frame];
}];

希望这有所帮助。

太棒了!我使用了你的代码的修改版来编写任何UIView的简单“hideControl”函数。它基本上将UIView的高度设置为0,但关键是,它使用了你的代码来使AutoLayout正确处理它(不像使用“someView.hidden = TRUE”)。因此,出现在隐藏控件下方并与其垂直间距相连的控件现在会向上移动以填补隐藏视图以前出现的空白处。 - Mike Gledhill

6

您可以在xib/storyboard中的UIView的自定义运行时属性中设置translatesAutoresizingMaskIntoConstraints类型Boolean,值为Yes。


4
在我的观点中,我有一个标签(Label)和文本(Text)。标签拥有平移手势,可以在拖动时很好地移动。但是当我使用文本框键盘时,标签会将其位置重置为自动布局中定义的原始位置。当我在Swift中为标签添加以下内容时,问题得以解决。我将此添加到viewWillAppear中,但实际上你可以在任何你可以访问目标字段的地方添加。
self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true

2
  • 在4.5中打开项目
  • 选择storyboard
  • 打开文件检查器
  • 在Interface Builder文档下取消勾选'使用自动布局'

如果您想为某些视图使用自动布局,可以将其拆分到多个storyboard中。


10
这将禁用整个故事板/ NIB 的自动布局。我想要的是一种方法(最好是编程方式),使得故事板/ NIB 中特定的子视图不使用自动布局,同时让其余部分执行故事板/ NIB 指定的操作。 - terriblememory
您可以使用多个故事板,根据需要调用具有/不具有自动布局的故事板://初始化storboard和详细视图控制器以进行显示 UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Storyboard" bundle:[NSBundle mainBundle]]; DetailViewController *dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName]; - Mike Bobbitt

1
我遇到过类似的情况,加入了一个使用自动布局启动的项目,但是我需要对几个视图进行动态调整。以下是对我有用的方法:
  1. 不要在界面构建器中放置视图或组件。

  2. 纯编程方式添加视图,从alloc/init开始,并适当设置它们的框架。

  3. 完成。


1

对我来说,通过编程方式创建子视图是有效的,在我的情况下,自动布局会影响到我需要围绕其中心旋转的视图,但一旦我通过编程方式创建了这个视图,它就可以正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接