2014-10-04 109 views
6

当使用autolayout尝试使用子视图填充视图时,我注意到一些非常奇怪的行为。这个想法非常简单:为视图添加一个子视图并使其使用父视图的所有宽度。Autolayout - 拉伸视图以填充其父视图

NSDictionary *views = @{ 
         @"subview":subView, 
         @"parent":self 
         }; 

这不起作用:

[self addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" 
               options:0 
               metrics:nil 
               views:views]]; 

子视图不使用父视图的整个宽度。

但这个工程:

[self addConstraints: 
     [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview(==parent)]|" 
               options:0 
               metrics:nil 
               views:views]]; 

我希望那些打算既会工作。那么为什么第一个例子不起作用?这是苹果公司建议在以下技术说明:

https://developer.apple.com/library/ios/technotes/tn2154/_index.html

编辑:(去除不相关的信息)

+0

它的工作原理,当我这样做。你看到了什么结果?您是否在控制台中收到任何警告? – rdelmar 2014-10-04 22:59:50

+0

没有自动布局警告。子视图只与其中最宽的元素一样宽,不占用父视图中的所有空间。当我起诉第二个例子时,它工作正常(然后使用所有父视图的宽度) – 2014-10-04 23:04:31

+0

您需要提供更多信息。你在子视图中有什么观点,你有什么限制吗? – rdelmar 2014-10-04 23:08:15

回答

1

如预期被此这是不工作的原因:

父视图是的UIScrollView,并且水平约束被设置为"H:|[contentView]|",滚动视图的contentSize将本身调整至所要求的宽度contentView,而不是相反。因此,自动布局引擎将首先确定contentView的尺寸,然后将父级(scrollview)的contentSize调整为相同的宽度。如果contentWidth比父级更窄,它将不会伸展,因为父级(scrollview)的contentSize将缩小到contentView的大小。

对于普通视图(不是滚动视图),父视图的宽度是固定的,所以它将首先布局父视图,然后是子视图。

通过将contentView的宽度强制为与父滚动视图相同的宽度,contentView将始终与父滚动视图的宽度相同,这正是我想要的(和预期的)。

+0

等等,你是说你实际上看到父视图缩小到子视图的宽度了吗? – algal 2014-10-13 22:52:13

+0

@algal是的,这正是发生的事情。在测试项目中重现非常容易。只需使用约束'H:| [label] |'将UILabel添加到UIScrollView,滚动视图的内容大小就会缩小到标签的大小。 – 2014-10-14 22:05:16

+0

好的。所以我没有我想象的那么完全错误。很高兴知道。 TN2154对我来说依然难以理解,尽管我现在至少读了6次。 – algal 2014-10-14 23:39:44

2

编辑:肯Thomases指出,我完全错了!

是的,您指定的两个约束系统都应使parentsubview(或parentcontentView)具有相同的宽度。

所以我会问,你绝对相信你所看到的是contentView未能填补父母?是否有可能在破损的案例中看到父母实际上正在缩小以适应contentView,并且您没有注意到它,因为父母具有透明或不可见的背景?

要检查此问题,请将contentViewparent设置为具有不同的不透明背景颜色。如果我错了,你会清楚地看到父区向外扩展的区域,其宽度大于contentView。如果我是对的,contentView将完全覆盖父级的宽度。

这就是为什么我(也许还振振有词)质疑有关规定实际上你所看到的:

在日志输出的主要区别是,对于损坏的案例,我们可以看到,拥有意想不到的约束的UIView到固定宽度的320

<NSLayoutConstraint:0x8433f8f0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x841b9f40(320)]> 

什么观点是?基于约束名称“UIView-Encapsulated-Layout-Width”,它与UIViewControllerWrapperView相关联,并且宽度保持为320(iPhone的宽度),我们可以推断出这个约束是由UIKit自动创建的将UICollectionView.view的大小限制为屏幕大小。查看所有的约束条件,你可以进一步看到这个width = 320约束是通过一系列约束(封装视图 - > DetailView - > DetailWeatherView)传递下来的,直到它最终确定了DetalWeatherView的宽度,这是你的parent,并且它使用超视图边缘偏移约束来拥抱contentView,因此它也应该具有320的相同宽度。

与此相反,对于有效的情况,您还可以看到应约束contentView.width使其与顶层封装布局视图的宽度相同的约束链。但是不同之处在于,任何地方都没有限制任何固定值为320的约束。相反,只有左对齐约束。

因此,我希望看到,在这两种情况下contentView.width == parent.width,但是,在破碎壳体宽度= 320,而在工作情况下,宽度是由低优先级的内部约束内contentView确定允许它膨胀到值大于320,也许是它的intrinsicContentSize。

+1

第二种情况下,你没有任何限制为320的宽度。 “WeatherTypeBoxView”和“AdditionalWeatherInfoBox”都被限制为160宽度并且彼此相邻并且相互超级视图的边缘相邻。所以,这也修复了宽度为320的层次结构。我不确定我们能够显示多少“额外”限制。我认为这两种情况都存在约束,只是它是多余的。在“-constraintsAffectingLayoutForAxis:'的意义上,布局系统可能不会考虑冗余约束来”影响布局“。 – 2014-10-09 18:39:18

+0

优秀点。 – algal 2014-10-09 18:45:12

4

这里是你发布你的“第一例”的约束:

first case

这里是你发布你的“第二例”的约束:

second case

我见这些结构有两个不同之处,我在图中用红色突出显示:

  1. 第一个(损坏的)案例在近根UIView 0x8433f8f0上有一个约束(0x8433f8f0),将其宽度固定为320个点。这是多余的,因为底层视图每个都限制在160个点,并且有足够的限制使得这些较窄视图的所有祖先的宽度为320个点。

  2. 第二(工作)的情况下具有约束(0x7eb4a670)钉扎的近底部UIView 0x7d5f3fa0的宽度的DetailWeatherView 0x7d5f3270宽度。这个约束是多余的,因为3fa0的左边缘被固定到3270的左边缘,而3fa0的右边缘被约束到3fa0的右边缘。我假设(==parent)谓词增加了这个约束。

所以你可能会想,每个案例都有一个冗余约束,那又怎么样?没什么大不了的,对吧?

不完全。在第二种情况下,冗余约束确实是无害的。您可以更改WeatherTypeBoxViewAdditionalWeatherInfoBox之一(或两者)的宽度,并且您仍然可以获得独特的解决方案。

在第一种情况下,如果视图的宽度不变,则冗余约束仅为无害。如果更改f8f0上的320宽度约束而不更改叶子视图上的160宽度约束,那么约束系统就没有解决方案。 Autolayout将打破解决该系统的限制条件之一,并且可能会破坏320宽度的限制。我们可以看到320宽度约束及其UIView-Encapsulated-Layout-Width注释是由系统强制强制这个视图层次结构符合某个容器的大小(也许是屏幕大小;也许是容器视图控制器施加的大小)。

我不知道为什么你的第一个案件有这个额外的顶级限制,而你的第二个案件没有。我倾向于相信你改变了导致这种差异的其他东西,但自动布局足够神秘,以至于我不能100%相信这一点。

如果您的目标是使此视图层次结构填充其容器并保持叶视图的宽度相等,那么在叶视图中除去160宽度约束并在它们之间创建一个等宽约束。

+0

正如在关于algal答案的评论中所提到的,我怀疑'UIView-Encapsulated-Layout-Width'约束在两种情况下都存在。请记住,'-constraintsAffectingLayoutForAxis:'不会返回视图上的所有约束,它只会返回影响布局的约束。在冗余约束的情况下,无论它是否包含,我都认为是任意的。 – 2014-10-09 19:50:33

+0

我看到了您的评论,但是由于我们正在寻找罪魁祸首,而且这种限制可能会导致布局问题,所以我现在将其视为嫌疑人。 – 2014-10-09 19:58:42

+0

如果存在冗余(但兼容)约束,您确定自动布局会破坏其中一个约束吗?我知道如果其中一个约束条件与另一个约束条件相矛盾,那么这两个约束条件中的一个将会被删除,但这对于非矛盾约束条件也是如此吗?如果是这样,那可以解释很多。 – 2014-10-09 20:37:55