默认今日小部件中的布局约束冲突

Posted

技术标签:

【中文标题】默认今日小部件中的布局约束冲突【英文标题】:Layout Constraint Conflicts in Default Today Widget 【发布时间】:2016-05-03 16:38:22 【问题描述】:

我在刚刚为我的应用程序创建的 Today Widget 中观察到关于 Autolayout 的非常奇怪的行为。 试图找到问题的根源,我最终创建了一个普通的 新 Xcode 项目(单视图应用程序)并添加了一个 Today Extension 作为新目标 - 甚至没有触及它。

当我在我的设备 (iPhone 6s) 上启动 Today Extension 时,首先发生的事情是控制台中引发了布局约束冲突:

2016-05-03 18:17:22.216 TodayExtension[10183:4611907] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<_UILayoutSupportConstraint:0x15c665320 V:[_UILayoutGuide:0x15c6657b0(0)]>",
    "<_UILayoutSupportConstraint:0x15c663890 V:|-(0)-[_UILayoutGuide:0x15c6657b0]   (Names: '|':UIView:0x15c6642a0 )>",
    "<_UILayoutSupportConstraint:0x15c666010 V:[_UILayoutGuide:0x15c666380(0)]>",
    "<_UILayoutSupportConstraint:0x15c666ed0 _UILayoutGuide:0x15c666380.bottom == UIView:0x15c6642a0.bottom>",
    "<NSLayoutConstraint:0x15c666b80 V:[_UILayoutGuide:0x15c6657b0]-(NSSpace(8))-[UILabel:0x15c6617c0'Hello World']>",
    "<NSLayoutConstraint:0x15c666bd0 V:[UILabel:0x15c6617c0'Hello World']-(NSSpace(8))-[_UILayoutGuide:0x15c666380]>",
    "<NSLayoutConstraint:0x15c552820 'UIView-Encapsulated-Layout-Height' V:[UIView:0x15c6642a0(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x15c666bd0 V:[UILabel:0x15c6617c0'Hello World']-(NSSpace(8))-[_UILayoutGuide:0x15c666380]>

您会注意到列表中的最后一个约束是UIView-Encapsulated-Layout-Height,它强制视图的高度为 0。我检查并发现引用的视图是小部件的根视图本身。因此,出于某种我无法理解的原因,系统在内部创建了一个 0 像素高度约束,该约束与 Interface Builder 中的视图设置冲突。 (当您在 Xcode 中创建一个全新的 Today 扩展时,您将看到,除了固定在小部件根视图的每一侧的 UILabel 之外,什么都没有。)

通常我会声称这是一个巨大的 ios 错误,但由于这是 Apple 用于创建 Today Widgets 的 默认 模板,我简直不敢相信它已经坏了。知道是什么导致了这种冲突行为以及如何解决它(正确)?


我基本上想通过赏金实现什么......

... 是要弄清楚是否有一种可靠的方式可以在 Today Widget 中使用自动布局而不引入一些变通方法和“肮脏的黑客攻击 strong>”,您不会在普通应用程序中使用。 (如果你最终添加了大量创建固定帧的约束并且不让内容动态增长,那不是 Autolayout 的真正想法,是吗?)


密切相关的问题是问题的一部分,可能会给出提示:Inconsistent Today Widget behavior breaks subview's height constraints

【问题讨论】:

你试过用widgetMarginInsetsForProposedMarginInsets添加边距吗? 是的,我做到了。我在上面链接的另一个问题中对此进行了解释。 @EICaptainv2.0:感谢您提供帮助。但首先,如果我删除底部约束,Today 小部件将不再随标签的内容增长(如果您在标签内放置 10 行文本,它将与小部件的边界重叠)。其次,我已经成功实现了一个带有一些肮脏黑客的小部件,但我在这里想要实现的是找到需要这些黑客的原因以及一个通用解决方案以正确使用 Autolayout今天的小部件。整个社区都可以从中受益,可以应用于任何小部件布局。 @EICaptainv2.0:再次感谢您的帮助。但是,如果您没有发布 cmets 并在我回复它们后再次删除它们,那就太好了。对于阅读此页面的其他用户,我的 cmets 将脱离上下文,没有人会理解发生了什么。 @Mischa 那是因为我会提供详细的答案... 【参考方案1】:

在 Apple 的一些股票 UIView 子类中,它们的实例化大小为零。您需要配置您的NSLayoutConstraints,以便他们可以正确响应此初始大小。过去,我将顶部或底部约束设为不等式,以便其余约束可以正确调整自身大小而不会破坏布局。

例如:将底部约束 (&lt;NSLayoutConstraint:0x15c666bd0 V:[UILabel:0x15c6617c0'Hello World']-(NSSpace(8))-[_UILayoutGuide:0x15c666380]&gt;) 设为 LessThanOrEqualToconstant 值为 8.0

【讨论】:

当我将底部约束从“等于”更改为“小于或等于”时,日志中的冲突消失了,是的,但是标签的定位不一致:我第一次运行小部件“Hello World”文本在我的小部件的标题和下一个小部件的标题之间垂直居中。但是当我隐藏通知中心并再次向下滑动时,文本突然上升了几个像素,现在更接近我自己的小部件的标题。所以感觉改变底部约束只是将问题(错误?)转移到另一个地方。 您可以在8.0 中添加一个额外的底部约束EqualTo 并赋予它较低的优先级。这样它会在需要时中断,但也会在可能的情况下强制底部间距为8.0 确实可以做到这一点。然而,我真的觉得我在这里用一个肮脏的黑客修复了一个系统错误。我简直不敢相信基本的自动布局(从上到下限制视图)不适用于 Apple 的默认今日小部件模板! (在创建今天的小部件时,我在 Autolayout 和 UI 方面经历了更多“异常”,这真的让我发疯!我称自己在 Autolayout 和感觉一半的正常自动布局规则不适用于今天的小部件。就像平行宇宙中的一组不同的自然法则之类的。另见:***.com/q/37010292/2062785)【参考方案2】:

我发现有用的方法是将视图限制在顶部和底部,将其水平居中并限制宽度。这让我在今天的小部件上取得了很好的效果。

【讨论】:

以上是关于默认今日小部件中的布局约束冲突的主要内容,如果未能解决你的问题,请参考以下文章

Swift UIView 小部件自动布局不起作用

使用自动布局为今天的 iOS8 扩展设置固定高度

Kivy 在布局末尾添加小部件

Flutter:小部件压缩优先级

如何切换网格布局中的小部件可见性?

使用自动布局正确对齐通知中心小部件中的元素