【问题标题】:iOS change auto layout constraints when device rotatesiOS 在设备旋转时更改自动布局约束
【发布时间】:2012-11-24 06:18:28
【问题描述】:

我想在设备旋转时修改布局约束。 我的UIViewController 由 2 个UIViews 组成,横向对齐,它们是水平对齐的, 在纵向上它们是垂直对齐的。

它确实有效,在willAnimateRotationToInterfaceOrientation 中,我删除了所需的约束并用其他约束替换它们以获得正确的布局...

但是有问题,在旋转过程中,自动布局在调用willAnimateRotationToInterfaceOrientation 之前开始打破约束,那么当设备重新定向发生时,我们打算在哪里替换我们的约束?

另一个问题是性能,经过几次旋转后,系统不再打破限制,但我的性能下降很大,尤其是在纵向模式下...

【问题讨论】:

  • 请在此处添加您的代码
  • @Makleesh : 是的,你是对的,使用自动布局时会出现很多问题,但我觉得它们很方便.. 无论如何,看起来这将是一种新的做事方式,最好进入现在已经晚了。
  • @Waseem :我真的没有要发布的代码......正如我所说的,约束在我的代码执行之前就被打破了,所以我真的不知道我可以发布什么代码!
  • 你应该接受其中一个答案——可能是 Rob 的——因为他肯定回答了你的问题。

标签: objective-c ios autolayout nslayoutconstraint


【解决方案1】:

在您的UIViewController 中覆盖-(void) viewWillLayoutSubviews 以更新您的约束,如下代码:

-(void) viewWillLayoutSubviews {
     switch(self.interfaceorientation)
     {
          case UIInterfaceOrientationLandscapeLeft:

              break;
          case UIInterfaceOrientationLandscapeRight:

              break;

          case UIDeviceOrientationPortrait:

              break;

          case UIDeviceOrientationPortraitUpsideDown:

              break;

     }
}

【讨论】:

  • layoutSubviews 是一种 UIView 方法,不确定这是要走的路,但谢谢!这个项目现在已经发货了,所以无论如何我都无法真正测试它,最接近你提议的方法是使用 UIViewController 中的 viewWillLayoutSubviews,我想我已经尝试过了,但没有成功..
  • 首先,如果您使用自动布局,您需要致电[super layoutSubviews]。其次,您不想修改layoutSubviews 中的约束,因为layoutSubviews 是在系统解决了约束之后发送的。在此处更改约束将在运行循环的下一轮触发另一个布局传递(以解决新约束)。
  • 看起来在这里实现/覆盖的正确方法是viewWillLayoutSubviews
  • 这很好用。只需设置新的约束常量,瞧!谢谢!
【解决方案2】:

在 Matthijs Hollemans 的帖子中对自动布局和旋转有很好的解释。 你可以在这里找到它: http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2

通常,您需要大约 4 个约束才能正确定位视图。如果我的视图大小不变,我更喜欢固定高度和宽度。之后,您可以使用前导和顶部空间约束来做任何您想做的事情。例如,您可以为视图的前导和顶部空间约束设置 IBOutlets:

@interface ViewController : UIViewController {
    IBOutlet NSLayoutConstraint *_leadingSpaceConstraint;
    IBOutlet NSLayoutConstraint *_topSpaceConstraint;
}

然后从出口控制并拖动到您的约束。 现在您可以直接从代码中更改视图约束:

_leadingSpaceConstraint.constant = NEW_CONSTRAINT_VALUE;

要提交更改,您需要调用:

[self.view layoutIfNeeded];

如果你想做动画:

[UIView animateWithDuration:0.25
                 animations:^{
                     [self.view layoutIfNeeded];
                 }];

我认为它将在 willAnimateRotationToInterfaceOrientation 中起作用,因为您不需要使用这种方法打破任何约束。

一些例子: 您有两个纵向的方形视图,一个在另一个下方。例如,将他们的“超级视图的前导空间”约束设置为 20。然后将“top space to superview constraint”设置为第一个视图的 20 和第二个视图的 120。这将是我们的默认设置。

然后,在旋转之后,您需要重新计算约束。现在将两个顶部约束设置为 20,将前导约束分别设置为 20 和 120。然后使用 layoutIfNeeded 提交更改。

我希望它会有所帮助。

【讨论】:

  • 我觉得你在那里违背了自动布局的目的,如果你设置一个固定的宽度和高度,并添加顶部/左侧空间进行定位,你所做的只不过是弹簧和支柱。当然,这样做没有任何约束,因为您没有添加任何将视图链接在一起的约束;例如,如果您必须管理多个屏幕尺寸/比例,则必须制定特殊情况,这是自动布局倾向于避免的!
  • 我认为这只是特例。你需要固定的大小和动态的位置——你可以得到它。你需要动态尺寸——你也可以得到它。自动布局允许您随时随地实现动态。弹簧和支柱 - 不是。
  • 在一些特殊情况下,您需要混合一些对旋转做出反应的硬编码尺寸。例如,在打开了分页的滚动视图中,您希望内部视图与屏幕的宽度相同,以便在分页时它们每个都与屏幕对齐。只要有这样的解决方法,就不值得关闭自动布局。自动布局为支持所有不同的设备分辨率节省了大量时间,而且未来的设备很可能会添加更多的分辨率来支持。
【解决方案3】:

willRotateToInterfaceOrientation:duration: 中,将setNeedsUpdateConstraints 发送到任何需要修改其约束的视图。

或者,创建一个UIView 子类。在您的子类中,注册接收UIApplicationWillChangeStatusBarOrientationNotification。收到通知后,请给自己发送setNeedsUpdateConstraints

这会在视图上设置needsUpdateConstraints 标志。在系统执行布局之前(通过发送layoutSubviews 消息),它会向任何设置了needsUpdateConstraints 标志的视图发送updateConstraints 消息。这是您应该修改约束的地方。创建一个UIView 子类并覆盖updateConstraints 以更新您的约束。

【讨论】:

  • 这非常酷并且完美无瑕。在我的实现中,我正在迭代 [视图约束] 并在添加特定于方向的约束之前删除每个约束。这是一次批发交换,动画变化看起来很棒。
  • 您是否必须对每个将修改其约束的视图进行子类化,或者您可以以某种方式完全从视图控制器中完成此操作?似乎非常非常常见的情况是更改一些宽度和高度以进行旋转更改,但是如果您必须为许多内部视图填充多个自定义类,那将非常难看。
  • 您可以为顶层视图创建一个自定义类,并将其提供给所有需要修改约束的子视图。然后,您可以在该自定义类的 updateConstraints 方法中设置所有约束。
  • @robmayoff,我创建了 UIView 子类,并注册了通知,获取了我的视图(即 ImageView)的出口,现在当通知触发时,我在该 ImageView 上设置了NeedsUpdateConstraints,并且 [[self ImageView ] updateConstraints] 在 updateConstraints 方法上设置,但什么也没发生...我该怎么办。?需要注意的一件事是,我在 xib 中为纵向和横向提供了约束。这在 iOS8 中运行良好,但在 iOS7 中不起作用。
  • 替换为viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多