我可以在同一个视图上使用 setFrame 和 autolayout 吗?
Posted
技术标签:
【中文标题】我可以在同一个视图上使用 setFrame 和 autolayout 吗?【英文标题】:Can I use setFrame and autolayout on the same view? 【发布时间】:2012-10-22 14:53:59 【问题描述】:我想为我的所有按钮添加内边距,因此我将 UIButton 子类化,并且在其他更改中,我想通过使用 setFrame 方法添加一个固定内边距。一切正常,除了 setFrame。我检查了一下,发现如果我取消选中该视图上的“使用 AutoLayout”,那么我可以使用 setFrame,它可以工作。有没有解决的办法?我真的很想使用自动布局,因为它有助于使应用程序在 iphone 5 和更早的设备上看起来都不错。但我也想在我的子类中使用 setFrame,让我的生活更轻松。
总结一下,我的问题是:我可以使用自动布局并以编程方式调整 UIView 的框架吗?
【问题讨论】:
【参考方案1】:是的,这是可以做到的。
如果您设置视图的translatesAutoresizingMaskIntoConstraints = YES
,则对setFrame:
的调用会在运行时自动转换为基于视图当前autoresizingMask
的布局约束。这让您可以混合使用基于框架的布局和基于约束的布局。
例如,您可以使用自动布局来定义视图的所有子视图的布局,但仍然调用setFrame:
来设置视图本身的大小和位置。从您的角度来看,您正在使用自动布局和直接框架操作混合进行布局。但系统实际上是使用约束来处理所有事情。
但是,使用translatesAutoresizingMaskIntoConstraints
有一个很大的警告。
当你这样做时,你仍然需要确保这些自动约束可以满足你的其余约束。
因此,例如,假设已经存在确定视图大小和位置的约束,然后您也设置translatesAutoresizingMaskIntoConstraints = YES
并调用setFrame:
。对setFrame:
的调用将在视图上生成新的约束,这可能会与已经存在的约束发生冲突。
(事实上,这个错误经常发生。如果您曾经看到一条日志消息抱怨约束冲突,并且其中一个约束是NSAutoresizingMaskLayoutConstraint
,那么您看到的是与自动约束的冲突。这个是一个容易犯的错误,因为translatesAutoresizingMaskIntoConstraints = YES
是默认值,所以如果您在代码中配置约束,如果您不想要这些自动约束,则需要记住将其关闭。)
相反,再次假设已经存在确定视图大小和位置的约束,但是在调用setFrame:
之前设置了translatesAutoresizingMaskIntoConstraints = NO
。在这种情况下,您的setFrame:
调用不会产生新的约束,因此单独的约束之间不会发生冲突。但是,在这种情况下,约束和您设置的帧值之间仍然存在“冲突”。下次调用 Auto Layout 时,它会看到视图上已经存在的约束,计算它们需要的框架值,并将框架设置为本身所需的值,从而破坏您手动设置的值。
有关更多详细信息,请查看 Apple 的 Cocoa Auto Layout Guide 中的“采用自动布局”部分。
【讨论】:
这可行,但我在日志中看到很多警告。任何人都可以建议使用这种方法的正确方法是什么?还是我应该忽略警告?谢谢 如果您看到关于不可满足约束的警告,这些可能是有意义的。如果您在视图上使用translatedAutoresizingMaskIntoConstraints=true
操作时看到它们,那么可能发生的情况是您已经有一些限制(可能在 IB 中设置)试图控制该视图的框架。框架上的那些旧约束与自动调整大小掩码自动生成的约束相互作用。在这种情况下,答案是消除那些旧的约束。如果您在 IB 中添加它们只是为了让 IB 在设计时关闭,您可以将它们设置为“占位符”以丢失它们。
@algal 如何摆脱“旧”约束?并且让子视图只监听 setFrame: 值,这样它们两个就不会冲突了。
这仍然适用于 ios 10 吗?我正在尝试为自定义容器 VC 中的子 VC 执行此操作,但它不尊重我设置的框架。
我注意到,如果您这样做,在许多情况下,您会希望从 的其他视图的框架中派生出框架的 CGRect
s > 使用自动布局。在这种情况下,您需要在其他视图完成其自动布局传递之后执行框架计算。在视图控制器中viewDidLayoutSubviews
是这个地方。在自定义视图中应使用layoutSubviews
。在这两种情况下,您都应该将帧计算放在 super
调用之后。可能值得将此添加到答案中,但我希望无论如何这是一个有用的评论!【参考方案2】:
对我来说最简单的事情是从其父视图中删除我想要移动/调整大小的视图,设置其frame
,然后将其添加回来。例如,在 UITableViewCell
子类中使用自定义 UILabel
:
[cell.myLabel removeFromSuperview];
cell.myLabel.frame = someFrameIGenerated;
[cell.contentView addSubview:cell.myLabel];
【讨论】:
没问题。虽然我觉得有义务告诉你我最终摆脱了这个并真正学习了如何在 IB 中使用约束。我不知道它们存在,现在制作复杂的布局似乎更加合理。 是的,我试过了,但无法在表头视图上获得约束。也许我应该再试一次。 通过这样做,您可以消除可能会搞砸其他事情的约束。累了。【参考方案3】:对我有用的方法是简单地将IBOutlet
添加到视图控制器中作为我的约束,然后更改插座上的constant
属性。
例如,要更改视图的 x 原点,请设置从该视图的前导约束到控制器的出口。换句话说,创建一个插座@IBOutlet var labelXOrigin: NSLayoutConstraint!
。然后,当您想调整 x 位置时,只需执行类似
self.labelXOrigin.constant = 20.0 // Or whatever origin you want to set.
【讨论】:
【参考方案4】:设置子视图框架的最佳方法是 viewWillLayoutSubviews 方法 自动布局项目。
设置属性 translateAutoresizingMaskIntoConstraints = true this 将在视图确实出现或在按钮上设置选项卡后工作,就在之后 视图确实出现了。
【讨论】:
【参考方案5】:如果您的应用不支持多种设备方向。
在 viewDidLoad 中设置要调整大小的视图的框架
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view.
[aView setFrame:CGRectMake(15, 15, 100, 100)];
然后在viewDidLayoutSubviews中:
-(void)viewDidLayoutSubviews
[self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
我不确定,但我认为如果您使用此解决方案,将一个方向切换到另一个方向可能会导致问题
【讨论】:
以上是关于我可以在同一个视图上使用 setFrame 和 autolayout 吗?的主要内容,如果未能解决你的问题,请参考以下文章
NSWindow 宽度未使用 setFrame(frame, display, animate) 更新
bringSubviewToFront + setFrame 不起作用
在 XIB 中添加手势时,iOS 应用程序崩溃并显示消息“-[UITapGestureRecognizer setFrame:]”
setTranslatesAutoresizingMaskIntoConstraints和setFrame组合使用导致的异常