Autolayout导致旋转上的小间隙

时间:2014-06-24 08:34:13

标签: ios rotation autolayout

我的应用程序使用自动布局创建一个界面,其中包含一个2:1容器(适合屏幕大小),内部有两个方框。下面是一个例子(只有左侧框可见):

user interface

当设备旋转时,代码会更新约束,以便从左到右(横向)或从上到下(纵向)定位框。代码工作得相当好,但界面有时会在轮换后像这样结束:

interface after rotation

如您所见,容器的背景可见左下角;它的严重程度各不相同(有时它更加明显)。

我设置了展示问题的small project;它包含一个故事板内的小视图层次结构,其中所有约束都在构建时被删除。

ViewController.mDualVideoView.m内创建/更新实际约束。

这些限制似乎对我来说非常准确,所以我不确定为什么会出现这些布局问题。

更新

删除取景器(上面屏幕截图中的橙色框)可以解决布局问题;它使用比例宽度&高度(例如width:= superview.width * 0.9)绘制插入的方框。不过,我不确定为什么这应该是一个问题。

2 个答案:

答案 0 :(得分:2)

虽然您的垂直约束不是问题,但我想指出它们缺少video1 / video2的高度限制:

[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_video1 attribute:NSLayoutAttributeHeight multiplier:1 constant:0]
[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:_video2 attribute:NSLayoutAttributeHeight multiplier:1 constant:0]

但是你的水平约束看起来不错,所以我采用了你的DualVideoView源代码并围绕它创建了一个最小的应用程序(source code at codepad.org)以重现问题。不幸的是,最小的应用程序没有显示你看到的那些差距,所以除非你能提供进一步的细节,否则我很难猜测。像往常一样,你可以做的最有用的事情是显示一个最小但完整的代码示例来展示问题 - 也许你可以从扩展我链接到上面的示例应用程序开始。

我能想到的主要问题是,在整个过程中出现了一个舍入错误,因为video1 / video2视图应该占用超级视图宽度的一半。

例如,如果DualVideoView实例获得奇数宽度,例如1023,会发生什么?假设半个点为floor,则1023的宽度的一半为511(511.5 floor ed)。 video1 / video2的总宽度变为1022,因此留下1个点的差距。但是,这个假设存在两个问题:

  1. 它没有解释垂直间隙,因为您的垂直约束不包括任何可能导致舍入错误的内容。
  2. 假设是错误的,自动布局不是floor(也不是ceil),它是四舍五入的。所以1023的宽度的一半是512(511.5向上舍入),这意味着如果有任何视频1 /视频2应该重叠并且应该没有间隙。
  3. 您可能会检查一些事项:

    • 如果旋转两次180°(即旋转回原位),是否还能看到间隙?如果间隙消失,则问题可能不是舍入误差,而是定位计算错误,这取决于设备/接口方向。

    • 如果使用Retina显示模拟器或设备进行测试,是否还能看到间隙?可能存在差异,因为在Retina显示器上,自动布局的舍入方式不同(它允许.5值和.25步的回合)。如果差距仍然存在并且您正在模拟器上进行测试,那么使用Pixie应用程序测量间隙是1或2像素宽可能会很有趣。

    • 如果您使用将视频1 /视频2与边缘对齐而不是超视图中心的约束(例如,将视频1的上/左边缘与其超视图的上/左边缘对齐),是否会产生影响? )?


    更新

    在GitHub示例项目中,我将问题跟踪到video1视图的小白色子视图的故事板中存在的约束。具体来说,问题在某种程度上与0.9乘数有关 - 如果你将乘数重置为默认的1.0而不是使用常数,例如-20,那么所有调整大小的问题都会神奇地消失。我说“神奇地”,因为我完全不知道为什么乘数应该产生这样的差异。如果我找到更多时间,我将再次采取措施,但现在这将是我的建议:使用常数值而不是乘数。

    我注意到的另一件事是,大多数(但不是全部)约束反过来表达了依赖关系。例如:

    [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.videoContainerView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0],
    

    此约束表示VC主视图(superview)的center.x取决于视频容器视图(子视图)的center.x.我觉得这是一种奇怪的方式来思考superview和subview之间的关系,我通常会想到这一点。不可否认,Auto Layout方程求解器似乎能够解决这个问题,但我仍然建议以自然依赖顺序编写约束。如果不出意外,它将帮助其他人更好地理解您的代码。


    更新2

    一些额外的研究:

    • 布局问题仅在iPhone模拟器中出现,但不在iPad模拟器中出现
    • 如果按比例调整大小的视图不是与中心对齐,而是与其超级视图(video1)的顶部和左侧边缘对齐,则布局问题会消失
    • 检查1)主视图,2)视频容器视图,以及3)video1视图(包含白色按比例调整的视图)和调试辅助constraintsAffectingLayoutForAxis从不显示任何涉及按比例调整大小的视图的约束 - 虽然删除视图或以不同方式对齐视图,但对布局有明显影响

    特别是最后一点让我相信这种约束组合会暴露自动布局引擎中的错误。我建议您使用类似于您在GitHub上发布的最小示例的内容向Apple提交错误报告。

答案 1 :(得分:0)

如果在Interface Builder中设置约束,您将收到有关缺失/冲突约束的警告。

此外,您可以模拟旋转,不同的屏幕尺寸,并获得那些丑陋的代码;)

对于这种特殊情况,你的比例和大小几乎是固定的,我宁愿实现layoutSubviews


如果子视图保持正方形,则他们不需要任何特殊调整或约束。您也可以根据需要将手动(layoutSubviews)与自动布局子视图混合使用。