Geo*_*org 61 margin uitableview ios autolayout
我正在使用UITableView与静态单元格分组的选项屏幕/场景.一切都在使用Autolayout在Xcode 6.1/iOS 8.1.x/Storyboard中完成.在表组中有混合类型的单元格,有两种类型会导致我出现问题:
在单元格#1上,我可以为标签和前导容器之间的左边距设置约束.在单元#2上,据我所知,我无法在Interface Builder中设置任何约束.我在单元格#1中的标签上设置了左边距,因此它与单元格#2中的标签对齐.iPhone上的一切看起来都不错,但是如果我在iPad上显示相同的表格,其中表格视图的容器大小是屏幕大小的一半,则单元格#2获得更多边距(动态?),而单元格#1保持绝对边距I在约束中设置.我还尝试使用属性"相对于边距"更改单元格#1中的左边距,但无效.
苹果手机:

iPad(桌面宽度= 1/2屏幕尺寸)

所以问题是:如何在单元格#1中设置标签的约束,使其与单元格#2对齐.
这里还有一个Xcode 6.1示例项目的链接,用于演示该问题.在iPhone和iPad上运行以查看差异:
https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip
这个问题可能与iPhone和iPad的布局静态表格单元格有关,但iOS 8也可能有所不同,因为现在一切都应该是自适应的.这就是我决定发布这个问题的原因.
Jon*_*ugg 150
在与苹果bug报告团队进行了多次示例项目和截图的对抗并解析了这个答案之后,我发现让自定义样式单元格在其边距上表现一致的解决方案就像默认的UITableViewCells一样,你必须做的以下(主要基于Becky的回答,我突出了它的不同之处以及它对我有用的原因):
在"布局边距"部分中,选中"保留超级视图边距" (不要单击加号)
(这是密钥)对单元格本身做同样的事情(内容视图的父级,如果你愿意的话)
按如下方式设置约束:Label.Leading = Superview.Leading Margin(常量为0)
现在所有单元格的标签都与默认单元格一致!这适用于我在Xcode 7及更高版本中,它包含我所提到的线程中提到的修复.IB和模拟器现在应该显示正确对齐的标签.
您也可以通过编程方式执行此操作,例如在View Controller的类中:
cell.preservesSuperviewLayoutMargins = true
cell.contentView.preservesSuperviewLayoutMargins = true
Run Code Online (Sandbox Code Playgroud)
或者你可以通过在启动时调用UIAppearance来设置它(我只知道Swift,对不起):
UITableViewCell.appearance().preservesSuperviewLayoutMargins = true
UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true
Run Code Online (Sandbox Code Playgroud)
正如Ethan所指出的那样,Apple自己的UIView文档描述preservesSuperviewLayoutMargins如下:
当此属性的值为
true,布局内容时也会考虑超级视图的边距.此边距会影响视图边缘与其超视图之间的距离小于相应边距的布局.例如,您可能有一个内容视图,其框架精确匹配其超级视图的边界.当superview的任何边距位于内容视图所代表的区域内以及它自己的边距时,UIKit会调整内容视图的布局以尊重superview的边距.调整量是确保内容也在superview的边距内所需的最小量.
因此,如果您希望单元格的内容与TableView的边距对齐(如果您愿意的话,它是非常祖父的),您需要拥有内容的两个优势,内容视图和表格单元本身,保留其自己的超级视图的边距.
为什么这不是默认行为让我感到惊讶:我觉得大多数不想定制所有内容的开发人员都会默认这种"继承".
我遇到了和你一样的问题并提出了解决方案.
首先,一点背景:从iOS 8开始,默认的表格视图单元格尊重单元格layoutMargins以适应不同的特征(也就是屏幕又称设备).例如,所有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;
}
Run Code Online (Sandbox Code Playgroud)
通过适应代码中的布局边距,您可以始终获得标题标签的正确填充.
您还可以看一下我已经尊重layoutMargins的UITableViewCell子类:https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
干杯
在阅读了现有答案并没有找到明显的编程解决方案之后,我进行了一些深入的研究,现在对面临此问题的其他任何人都有很好的答案。
首先,没有其他答案暗示的设置preservesSuperviewLayoutMargins到单元格视图或内容视图的必要。虽然默认值为,但将其更改为没有任何明显的效果。 falsetrue
使其真正起作用的关键是的layoutMarginsGuide属性UIView。使用此值,我们可以轻松地将leadingAnchor任何子视图的固定到leadingAnchor指南的。这就是它在代码中的外观(很可能是IB在Jonas的回答中在幕后所做的事情)。
在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()
}
Run Code Online (Sandbox Code Playgroud)
Swift 4.1更新
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraint(equalTo: leading).isActive = true
subview2.leadingAnchor.constraint(equalTo: leading).isActive = true
super.updateConstraints()
}
Run Code Online (Sandbox Code Playgroud)
就这样!如果您要开发iOS 9之前的iOS版本,则需要替换布局锚点,而使用layoutMarginsinset。
注意:如果您希望使用更简洁的语法,我写了一个库来使锚点更漂亮。它称为SuperLayout,可在Cocoapods上使用。在源文件的顶部,导入SuperLayout:
import SuperLayout
Run Code Online (Sandbox Code Playgroud)
然后在你的布局块,使用~~,??和??对销约束:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
subview1.leadingAnchor ~~ margins.leadingAnchor
subview2.leadingAnchor ~~ margins.leadingAnchor
super.updateConstraints()
}
Run Code Online (Sandbox Code Playgroud)
ios 11+:让margins = contentView.directionalLayoutMargins ...以防您需要开箱即用地适应LTR和RTL。我认为大多数人确实需要这样做。
| 归档时间: |
|
| 查看次数: |
29381 次 |
| 最近记录: |