Ios 如何调整UITableView tableHeaderView的左右插图或页边距?

Ios 如何调整UITableView tableHeaderView的左右插图或页边距?,ios,uitableview,uiedgeinsets,Ios,Uitableview,Uiedgeinsets,我有一个“普通”风格的UITableView。我正在将一个视图设置为表视图的tableViewHeader。该表还显示了右侧下方的截面索引 我的问题是如何插入页眉视图的左边缘和右边缘,以考虑在iPhone X上运行时的安全区域插入(横向)和表视图的节索引(如果有) 我创建了一个简单的测试应用程序,它添加了一些虚拟行、一个节标题和节索引 下面是我使用UILabel创建简单标题视图的代码。我真正的应用不会使用标签,而是使用自定义视图 let label = UILabel() label.font

我有一个“普通”风格的UITableView。我正在将一个视图设置为表视图的
tableViewHeader
。该表还显示了右侧下方的截面索引

我的问题是如何插入页眉视图的左边缘和右边缘,以考虑在iPhone X上运行时的安全区域插入(横向)和表视图的节索引(如果有)

我创建了一个简单的测试应用程序,它添加了一些虚拟行、一个节标题和节索引

下面是我使用UILabel创建简单标题视图的代码。我真正的应用不会使用标签,而是使用自定义视图

let label = UILabel()
label.font = UIFont.systemFont(ofSize: 30)
label.backgroundColor = .green
label.text = "This is a really long Table Header label to make sure it is working properly."
label.sizeToFit()
tableView.tableHeaderView = label
在没有任何特殊尝试来修复左右边缘的情况下,iPhone X模拟器中的结果如下:

Portait:

景观:

请注意,无需任何额外的努力,单元格和节标题将获得所需的插入,但标题视图不会

我希望标题视图的左边缘与节标题和单元格的左边缘对齐

我希望页眉视图的右边缘在与节索引的左边缘相交的位置停止。请注意,肖像图片似乎已经这样做了,但如果仔细观察,可以看出标题视图一直延伸到表视图的右边缘。你看不到省略号的第三个
,你几乎看不到章节标题视图后面的绿色

我曾尝试将以下内容添加到我的表视图控制器中:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if let header = tableView.tableHeaderView {
        var insets = header.layoutMargins
        insets.left = tableView.layoutMargins.left
        insets.right = tableView.layoutMargins.right
        header.layoutMargins = insets
    }
}
那条守则没有效力

我应该设置哪些属性来确保页眉视图的左边缘和右边缘根据需要缩进?是否存在应应用的约束条件

请注意,我所做的一切都是代码。因此,请不要发布任何需要故事板或xib文件的解决方案。欢迎使用Swift或Objective-C回答


对于任何想要复制此项目的人,请创建一个新的单视图项目。调整主情节提要以使用UITableViewController而不是平面UIViewController,并对
ViewController
使用以下命令:

import UIKit

class ViewController: UITableViewController {

    // MARK: - UITableViewController methods

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        cell.textLabel?.text = "Row \(indexPath.row)"
        cell.accessoryType = .disclosureIndicator

        return cell
    }

    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Section Header"
    }

    override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
        let coll = UILocalizedIndexedCollation.current()

        return coll.sectionIndexTitles
    }

    override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
        return index
    }

    // MARK: - UIViewController methods

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.sectionIndexMinimumDisplayRowCount = 1

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")

        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 30)
        label.backgroundColor = .green
        label.text = "This is a really long Table Header label to make sure it is working properly."
        label.sizeToFit()
        tableView.tableHeaderView = label
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        if let header = tableView.tableHeaderView {
            var insets = header.layoutMargins
            insets.left = tableView.layoutMargins.left
            insets.right = tableView.layoutMargins.right
            header.layoutMargins = insets
        }
    }
}

将标签添加到tableview后,需要向标签添加一些自动布局约束:

…
tableView.tableHeaderView = label
//Add this
label.translatesAutoresizingMaskIntoConstraints = false
label.leadingAnchor.constraint(equalTo: (label.superview?.safeAreaLayoutGuide.leadingAnchor)!).isActive = true
label.trailingAnchor.constraint(equalTo: (label.superview?.safeAreaLayoutGuide.trailingAnchor)!).isActive = true
此外,如果要查看标签中的所有文本,请使用
label.numberOfLines=0

您可以删除添加到
viewdilayoutsubviews
的代码

更新: 为了好玩,我在一个操场上做了一些实验,发现使用
layoutMarginsGuide
并没有将标题标签的后缘推得足够远(我认为它在iPhone X上出现了,但可能不是在所有设备上,或者操场的行为有点不同)。我确实发现,对于至少有一个单元格的表视图,我可以使用
aCell.contentView.bounds.width
,减去表视图的宽度,然后将结果除以2,标题标签将非常好地位于节索引旁边。因此,我编写了一个用于设置约束的助手函数。表视图是可选的,因此该函数可以与任何具有superview且需要保持在安全区域内的视图一起使用。如果传入一个表视图,它可以有一个节索引,也可以没有,但它至少需要在第0行第0节有一个单元格:

func constrain(view: UIView, inTableView aTableView: UITableView?) {
    guard let container = view.superview else {
        print("Constrain error! View must have a superview to be constrained!!")
        return
    }
    view.translatesAutoresizingMaskIntoConstraints = false
    view.leadingAnchor.constraint(equalTo: container.safeAreaLayoutGuide.leadingAnchor).isActive = true
    if let table = aTableView, let aCell = table.cellForRow(at: IndexPath(row: 0, section: 0)) {
        let tableWidth = table.bounds.width
        let cellWidth = aCell.contentView.bounds.width
        view.trailingAnchor.constraint(equalTo: table.safeAreaLayoutGuide.trailingAnchor, constant: cellWidth - tableWidth).isActive = true
    } else {
        view.trailingAnchor.constraint(equalTo: container.safeAreaLayoutGuide.trailingAnchor).isActive = true
    }
}

我在使用这个时确实发现了一个问题。在文本中使用设置为0行的标签时,它会覆盖该部分的第一个部分标题和第一个单元格。它需要一点滚动,让他们从标题下了。但是,将标签剪切到一行效果非常好。

对于没有节索引的UITableView:

label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    label.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    label.trailingAnchor.constraint(equalTo: tableView.layoutMarginsGuide.trailingAnchor)
])
对于具有节索引的UITableView:

label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    label.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    label.trailingAnchor.constraint(equalTo: tableView.layoutMarginsGuide.trailingAnchor)
])

根据安全区域布局指南设置引导锚是完美的。如果表视图没有节索引,那么您需要的是后续锚定的解决方案。但是对于具有节索引的表视图,安全区域跟踪锚点是不正确的。然后我使用layoutMarginGuide作为尾部锚点,这在有节索引的情况下是完美的。因此,正确的尾部锚点需要基于表视图是否显示节索引。这对我不起作用。1-为什么代码要在
viewdilayoutsubviews
中创建和应用标题视图?属于
viewDidLoad
的。2-如果表没有节索引,则拖曳锚会留下一个间隙。3-主播在所有情况下都留下了一个不希望出现的空白,除了在风景中的iPhoneX。看来,昨天对我来说已经太晚了;-)正如您在对Mikeswan答案的评论中所指出的,必须根据表视图是否具有节索引设置不同的尾部约束。我删除了我的旧答案,并添加了两个选项。我知道这个问题基本上已经被梅克斯万回答了,但与其回答得不好,我宁愿这样。如果你认为这个答案只是重复的,没有任何价值,我很乐意删除它。