【问题标题】:Subviews layer transform and layoutSubviewsSubviews 图层变换和layoutSubviews
【发布时间】:2014-09-28 09:59:19
【问题描述】:

我的问题与

有关

UIView/CALayer: Transform triggers layoutSubviews in superview

据报道,来自苹果的 TSI 回复:

通常,更改视图(或图层)的几何属性会 在视图层次结构中触发一连串的布局失效 因为父视图可能具有涉及的自动布局约束 修改的孩子。请注意,自动布局以某种形式处于活动状态 无论您是否明确启用它。

在我的情况下,我有一个非常简单的视图层次结构,其中视图 A 包含视图 B

A 的 layoutSubviews 中,我正在设置 B 的框架。

当我在 B 的支持层上执行动画(变换和不透明度)时,有时会调用 A 的 layoutSubviews。这显然是一个问题,因为我在 A 的 layoutSubviews 中设置了 B 的框架,这会破坏动画。

如何避免B的布局和动画的这种冲突?

【问题讨论】:

  • 从您链接到的那个页面:每次我更改转换时,如何避免从超级视图到 layoutSubviews?没有办法绕过这种行为。它是 UIKit 内部簿记的一部分,需要保持视图层次结构一致。
  • (似乎暗示你在动画变换时不能绕过这个)
  • 是的,你是对的。很明显,无法绕过这种行为。但这意味着不可能在受自动布局影响的视图和不受影响的视图中划分层次结构。
  • 来自UIView documentation:“只有当子视图的自动调整大小和基于约束的行为不能提供您想要的行为时,您才应该覆盖此方法。您可以使用您的实现来设置框架矩形直接访问您的子视图。”我想您可以做的一件事是对动画进行手动条件检查;即,如果 B 正在制作动画,则让此方法跳过 B,使用通过动画调用设置/取消设置的 BOOL 标志
  • 我用我找到的围绕这个主题的解决方案添加了一个答案

标签: ios objective-c uiview core-animation autolayout


【解决方案1】:

我发现有很多方法可以解决这个问题:

1) 临时保存变换,更改框架,然后重新应用变换:

[super layoutSubviews];

//backup the transform value before the layout
CATransform3D transform = self.internalView.layer.transform;

//Set identity and update all the necessary frames
self.internalView.layer.transform = CATransform3DIdentity;
self.internalView.frame = self.bounds;

//set back the transform
self.internalView.layer.transform = transform;

2) 在不接触框架的情况下更改视图的边界和中心。边界和中心似乎不影响变换。有意义,因为框架是在内部计算的,读取层的边界、位置、变换、锚点。

self.internalView.bounds = self.bounds;
self.internalView.center = CGPointMake(floorf(CGRectGetWidth(self.bounds)/2.0f),        floorf(CGRectGetHeight(self.bounds)/2.0f));

3) Apple 在 TSI(此处报告 UIView/CALayer: Transform triggers layoutSubviews in superview)建议

"将单元格内容包装在中间视图中。当您修改 这个中间视图的变换,只有单元格的布局应该是 无效,因此不会调用昂贵的布局方法。

如果这不起作用,请创建一些机制来向您的 实际需要(或不需要)做的昂贵的布局方法 工作。这可能是您在进行唯一更改时设置的属性 是变换。”

4) 我还尝试关闭自定义视图的子视图的完全自动布局。您可以从obj.io 阅读这篇非常好的文章,其中解释说,如果您从 layoutSubviews 实现中删除对 [super layoutSubviews] 的调用,您将选择退出自动布局自定义视图及其所有子视图。

需要注意的是,如果您将带有约束的视图添加为子视图,自动布局系统将引发如下异常:

*** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“自动布局仍然存在” 执行 -layoutSubviews 后需要。 MyView 的实现 -layoutSubviews 需要调用 super。'

如果您有简单的布局逻辑,则解决方案 1 和 2 很好。如果您的布局逻辑很广泛,您可以实现 3 或 4 并参考其他问题 UIView/CALayer: Transform triggers layoutSubviews in superview

【讨论】:

  • 解决方案 1 在 iOS 8 中运行良好,但在 iOS 7 中表现不同。知道为什么吗?更新 - 结果我只需要为 iOS 8 应用它;没有它,iOS 7 也能正常工作。
  • 创建额外的 internalView 肯定对我有帮助!谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多