UITableViewCell与iPhone和iPad上的自动布局左边距不同
我正在使用静态单元格的分组UITableView
的选项屏幕/场景。 一切都在Xcode 6.1 / iOS 8.1.x / Storyboard使用Autolayout完成。 在表格组里有混合types的单元格,有两种types会引起我的问题:
- 单元格与自定义样式和
- 具有样式“右侧细节”
在单元格1上,我可以为标签和前导容器之间的左边距设置一个约束。 就我所知,在单元#2上,我无法在Interface Builder中设置任何约束。 我已经在单元格#1中的标签上设置了左边距,使其与单元格#2中的标签alignment。 一切都在iPhone上看起来不错,但如果我在iPad上显示表视图的容器的大小是屏幕大小的一半的同一张表,单元格#2获得更多的余量(dynamic?),而单元格1保持绝对余量我在约束中设置。 我也尝试改变单元格#1的左边距的属性“相对于边距”,但无济于事。
苹果手机:
iPad(桌面宽度= 1/2屏幕尺寸)
所以问题是:我如何设置单元格#1中的标签的约束,以便它像单元格#2一样alignment。
这里也是一个Xcode 6.1示例项目的链接,演示了这个问题。 在iPhone和iPad上运行以查看区别:
https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip
这个问题可能与iPhone和iPad的Layout静态表格单元格有关 ,但是对于iOS 8来说也可能不同,因为现在一切都应该是自适应的。 这就是为什么我决定发表这个问题。
如何解决它
在与许多示例项目和屏幕截图的苹果bug报告团队作斗争之后,我已经发现解决scheme让您的自定义样式单元格对于他们的边缘行为一致,就像默认的UITableViewCells,你必须做的以下(主要基于贝基的回答 ,我已经强调了什么是不同的,什么使它为我工作):
- 在IB中select您的单元格的内容视图
- 转到尺寸检查器
-
在“版面边距”部分中, 选中“保留超视图边距”(不要单击加号)
-
(这里是关键) 对单元格本身也是一样的 (如果你愿意的话,内容视图的父类)
-
设置你的约束如下:Label.Leading = Superview.Leading Margin(常量为0)
现在,您的所有单元格都将具有与默认单元格一致的标签! 这对我来说在Xcode 7中起作用,它包括我提到的线程中提到的修复。 IB和模拟器现在应该显示正确alignment的标签。
你也可以用编程的方式做一些这样的事情,例如在视图控制器的类中:
cell.preservesSuperviewLayoutMargins = true cell.contentView.preservesSuperviewLayoutMargins = true
或者你可以通过在启动时调用UIAppearance来设置它(我只知道Swift,对不起):
UITableViewCell.appearance().preservesSuperviewLayoutMargins = true UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true
如何和为什么它的作品
正如Ethan所指出的那样,Apple自己的UIView文档描述了如下所示的preservesSuperviewLayoutMargins
了SuperviewLayoutMargins:
当这个属性的值为
true
,在布置内容时也会考虑超视图的边距。 此边距会影响视图边缘与其俯视图之间的距离小于相应边距的布局。 例如,您可能有一个内容视图,其框架与其超级视图的边界精确匹配。 当任何超视图的边距都在内容视图和自己的边距表示的区域内时,UIKit会调整内容视图的布局以尊重超视图的边距。 调整的金额是确保内容也在监视范围内所需的最小金额。
因此,如果你希望你的单元格的内容与TableView的边距一致(如果你愿意的话,它是一个很大的祖父母),你需要让你的内容的两个方面,内容视图和表格单元本身,保留自己的超级视angular的边缘。
为什么这不是默认行为让我感到惊讶:我觉得像大多数不想自定义所有东西的开发人员默认会希望这种“inheritance”。
我遇到了同样的问题,并提出了一个解决scheme。
首先,有一点背景:自iOS 8以来,默认的表格视图单元格尊重单元格的layoutMargins
以适应不同的特性(又名屏幕aka设备)。 例如,所有iPhone(当在表单中显示时iPhone 6 Plus除外)的版面边距为{8, 16, 8, 16}
。 在iPad上,他们是{8, 20, 8, 20}
。 所以现在我们知道有4个像素差异,这很可能是您的自定义表格视图单元不尊重。
当layoutMargins更改时,表格视图单元格子类需要调整左边距约束。
以下是相关的代码片段:
- (void)layoutMarginsDidChange { [super layoutMarginsDidChange]; self.leftLayoutMarginConstraint.constant = self.layoutMargins.left; self.rightLayoutMarginConstraint.constant = self.layoutMargins.right; }
适应代码中的布局边距可以使您始终为标题标签填充正确的内边距。
你也可以看看我已经尊重layoutMargins的一个UITableViewCell子类: https : //github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
干杯
在阅读了现有的答案之后,并没有find一个明显的程序化解决scheme,我做了一些更深入的挖掘,现在对于面临这个问题的任何其他人都有一个很好的答案。
首先,没有必要像其他 答案所暗示的那样将preservesSuperviewLayoutMargins
的SuperviewLayoutMargins设置为单元格的视图或内容视图。 虽然默认值为false
,但将其更改为true
并没有显而易见的效果。
使这实际工作的关键是UIView
上的layoutMarginsGuide
属性。 使用这个值,我们可以很容易地将leadingAnchor
视图的leadingAnchor
到指南的leadingAnchor
。 下面是它在代码中的外观(在Jonas的回答中,很可能是IB在做幕后工作)。
在UITableViewCell
子类中,你可以这样做:
override func updateConstraints() { let margins = contentView.layoutMarginsGuide let leading = margins.leadingAnchor subview1.leadingAnchor.constraintEqualToAnchor(leading).active = true subview2.leadingAnchor.constraintEqualToAnchor(leading).active = true super.updateConstraints() }
就这样! 如果您正在开发iOS版本之前的iOS版本,则需要replace布局锚点,然后使用layoutMargins
插入。
注:我写了一个库,使锚定更漂亮,如果你更喜欢一个更清晰的语法。 这叫做SuperLayout ,可以在Cocoapods上使用。 在源文件的顶部,导入SuperLayout
:
import SuperLayout
然后在你的布局块中,使用~~
, ≤≤
和≥≥
引脚约束:
override func updateConstraints() { let margins = contentView.layoutMarginsGuide subview1.leadingAnchor ~~ margins.leadingAnchor subview2.leadingAnchor ~~ margins.leadingAnchor super.updateConstraints() }
我能够通过执行以下操作来获取具有与标准单元格alignment的自定义样式的单元格:
- 在“文档大纲”中,为自定义样式的单元格select“内容视图”。
- 转到尺寸检查器。
- 在“Layout Margins”下拉菜单中,点击“Preview Superview Margins”旁边的小加号。
- select“常规宽度x常规高度”的iPad大小类别。
- 选中“保留Superview边距”旁边的checkbox。
- 通过更新帧来解决任何自动布局警告。
这在Xcode 7中适用于我; 我希望它也能在Xcode 6中工作。
在iPad Air 10.1.1上testing时遇到了这个问题。 表头比预想的要进一步缩进,在横向上更糟糕。 但是,他们在OS 11以上的手机都很好。
令人惊讶的解决scheme是在创build表之后的下面一行代码(对不起,我只用C#工作,但是很容易计算出Obj-C和Swift等价物):
myTableView.SeparatorInset = myTableView.SeparatorInset;
然后,一切都缩进,因为它应该是!