使用自动布局实现按钮的网格布局

Posted

技术标签:

【中文标题】使用自动布局实现按钮的网格布局【英文标题】:Achieving Grid Layout of Buttons with Autolayout 【发布时间】:2014-02-16 20:22:37 【问题描述】:

我正在尝试实现与 Apple 内置计算器应用程序非常相似的按钮布局:

我正在使用自动布局来定位按钮,并在每个按钮上绘制一个 0.5 像素的边框,目标是按钮之间有 1 像素的间隙(如 calc 应用,特写显示上方的像素,来自视网膜设备)。

边框应用:

    btn.layer.borderWidth=0.5f;
    btn.layer.borderColor=[[UIColor blackColor] CGColor];

并且布局是使用 Interface Builder 设置的。

它几乎可以工作;但按钮之间的间隙存在一些差异 - 例如“1,2,3,thru”行和“4,5,6,and”行之间的间隙为 2 个像素,但“7”之间的间隙,8,9" 和 "cl,0,@" 行只有一个像素。

约束是:

顶部黑色区域具有固定高度 所有按钮高度相同 在数字行中,数字按钮设置为相同宽度,THRU、AND、ALL OFF 和 ENTER 按钮设置为相同的固定宽度 顶行按钮固定在黑色区域的底部,底行固定在超级视图的底部 在 IB 中,所有按钮都位于相互对接的位置。

在界面生成器和运行时,我没有看到任何自动布局错误;自动布局信息的调试器转储给了我:

po [[UIWindow keyWindow] _autolayoutTrace]

*<UIWindow:0x10908a560> - AMBIGUOUS LAYOUT
|   *<UILayoutContainerView:0x109136140>
|   |   *<UINavigationTransitionView:0x10908ef80>
|   |   |   *<UIViewControllerWrapperView:0x109138870>
|   |   |   |   *<UIView:0x1090e6d10>
|   |   |   |   |   *<UILabel:0x1090d5bb0>
|   |   |   |   |   *<UIButton:0x1090d27e0>
|   |   |   |   |   |   <UIButtonLabel:0x1091c9190>
|   |   |   |   |   *<UIButton:0x1090844c0>
|   |   |   |   |   |   <UIButtonLabel:0x1091c7990>
|   |   |   |   |   *<UIButton:0x109088b60>
|   |   |   |   |   |   <UIButtonLabel:0x1091c6190>
|   |   |   |   |   *<UIButton:0x1090e2ce0>
|   |   |   |   |   |   <UIButtonLabel:0x1091c4990>
|   |   |   |   |   *<UIButton:0x1090e4e50>
|   |   |   |   |   |   <UIButtonLabel:0x1091c3190>
|   |   |   |   |   *<UIButton:0x1090db730>
|   |   |   |   |   |   <UIButtonLabel:0x1091c1990>
|   |   |   |   |   *<UIButton:0x109068f50>
|   |   |   |   |   |   <UIButtonLabel:0x1091c0190>
|   |   |   |   |   *<UIButton:0x10906db80>
|   |   |   |   |   |   <UIButtonLabel:0x1091be990>
|   |   |   |   |   *<UIButton:0x1090d23a0>
|   |   |   |   |   |   <UIButtonLabel:0x1091bd190>
|   |   |   |   |   *<UIButton:0x1090c8520>
|   |   |   |   |   |   <UIButtonLabel:0x1091bb990>
|   |   |   |   |   *<UIButton:0x1090c9090>
|   |   |   |   |   |   <UIButtonLabel:0x1091ba190>
|   |   |   |   |   *<UIButton:0x1090c5680>
|   |   |   |   |   |   <UIButtonLabel:0x1091b8990>
|   |   |   |   |   *<UIButton:0x1090d7fa0>
|   |   |   |   |   |   <UIButtonLabel:0x1091b7190>
|   |   |   |   |   *<UIButton:0x1090cc820>
|   |   |   |   |   |   <UIButtonLabel:0x1091b5990>
|   |   |   |   |   *<UIButton:0x10909dda0>
|   |   |   |   |   |   <UIButtonLabel:0x1091b4190>
|   |   |   |   |   *<UIButton:0x1090c8090>
|   |   |   |   |   |   <UIButtonLabel:0x1091b2990>
|   |   |   |   |   *<UIButton:0x1090c8e30>
|   |   |   |   |   |   <UIButtonLabel:0x1091b1190>
|   |   |   |   |   *<UIButton:0x1090d5390>
|   |   |   |   |   |   <UIButtonLabel:0x1091af990>
|   |   |   |   |   *<UIButton:0x10d30d260>
|   |   |   |   |   |   <UIButtonLabel:0x1091ae190>
|   |   |   |   |   *<UIButton:0x10909a6a0>
|   |   |   |   |   |   <UIButtonLabel:0x1091ac990>
|   |   |   |   |   *<UIButton:0x1090cca40>
|   |   |   |   |   |   <UIButtonLabel:0x109161160>
|   |   |   |   |   *<UIButton:0x10d30ea90>
|   |   |   |   |   |   <UIButtonLabel:0x109156460>
|   |   |   |   |   *<UIButton:0x1090da9e0>
|   |   |   |   |   |   <UIButtonLabel:0x109177ad0>
|   |   |   |   |   *<_UILayoutGuide:0x1090e6dd0> - AMBIGUOUS LAYOUT
|   |   |   |   |   *<_UILayoutGuide:0x1090ce080> - AMBIGUOUS LAYOUT
|   |   <UINavigationBar:0x10907da60>
|   |   |   <_UINavigationBarBackground:0x109087240>
|   |   |   |   <_UIBackdropView:0x1090899f0>
|   |   |   |   |   <_UIBackdropEffectView:0x10908b110>
|   |   |   |   |   <UIView:0x10908bbb0>
|   |   |   |   <UIImageView:0x1090877a0>
|   |   |   <UINavigationItemView:0x10916bc30>
|   |   |   |   <UILabel:0x10917f810>
|   |   |   <UINavigationItemButtonView:0x1090ee060>
|   |   |   |   <UILabel:0x1090ee5d0>
|   |   |   <_UINavigationBarBackIndicatorView:0x109098c80>

谁能提供有关如何使用自动布局实现这样的“像素完美”布局的任何提示?还是我应该以编程方式执行此操作?

【问题讨论】:

我怀疑根据您的限制没有可用的额外 1 像素。这就是为什么你会得到差异?如果将顶部黑色视图的高度降低 1 个像素会发生什么? 顶部黑色视图被限制为 >=100px 高 - 我只是尝试将其设置为 >=99 和 =99 和 =30,但问题仍然存在。 你有一个模棱两可的布局? 我没有看到任何报告的界面生成器中布局不明确的问题;我确实从调试器中获得了上面的报告,这表明 UILayoutGuides 具有“不明确的布局”,但我没有任何参考布局指南的内容,所以不知道如何消除它 你能澄清一下你是给视网膜还是非视网膜尺寸。如果您要提供视网膜,我认为您需要在第一句话中说“pt”而不是“px”,以便您的描述加起来。只是想确保我没看错问题。 【参考方案1】:

图层边界是在视图边界内绘制的,因此您不会看到按钮之间的“间隙”,而是两个边界相互邻接的效果。这在非视网膜模拟器或设备中不起作用,因为它无法绘制半像素,并且 Autolayout 不会在半像素上对齐视图。

对于像上面这样的布局,我会为按钮(或一个按钮,并使其他按钮相等)提供固定高度,并让黑色视图占据剩余空间。最好在全屏布局中至少包含一个(理想情况下,恰好是一个)变量元素,以覆盖舍入误差。

目前听起来您有一个固定元素(黑色视图),并且按钮基本上是“取剩余高度并在彼此之间划分”,这只有在剩余高度完全划分时才有效。

【讨论】:

我希望视图划分剩余空间的原因是因为当旋转到横向时,我希望黑色区域具有最小尺寸,并且按钮填充剩余空间空间 - 没有那个按钮最终要么横向太大或纵向太小 - 再次像计算器应用程序。 这是为 iPhone 设计的吗?平板电脑?您支持哪些屏幕尺寸? iPhone,为 ios7 构建,因此支持 iPhone 4、4S、5 视网膜显示器。【参考方案2】:

我尝试将视图之间的水平/垂直间距设置为 0.5。父视图的颜色作为边框颜色。它在 IB 中看起来很难看,它无法正确布局视图,但在设备上生成的布局看起来很完美。

在界面生成器中:

在模拟器上:

约束有点棘手。对于每一行

设置第一个按钮的高度 为所有按钮设置相同的高度 为所有按钮设置相同的宽度(对于带有橙色按钮的行略有不同) 对齐所有按钮的上边缘 对齐所有按钮的底部边缘 将所有按钮之间的前导和尾随空格(包括超级视图的空格)设置为 0.5 将第一个按钮的顶部空间(前一行)设置为 0.5

您可以一次将约束应用于多个项目。为了在按钮之间应用前导/尾随空格,请在应用之前将它们按所需顺序放置,不要交叉。

【讨论】:

以上是关于使用自动布局实现按钮的网格布局的主要内容,如果未能解决你的问题,请参考以下文章

使用 PySide 在灵活的网格布局中布局 QPushButtons [重复]

使用自动布局创建一个大正方形的网格

异构网格布局

Android组件式开发——实现网格布局的RadioButton矩阵

2x2 按钮网格布局

KIVY:如何清除所有子项的网格布局