2

我有一个“普通”风格的 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模拟器中的结果如下:

肖像:

在此处输入图像描述

景观:

在此处输入图像描述

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

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

我希望标题视图的右边缘在它与部分索引的左边缘相交处停止。请注意,肖像图片似乎已经这样做了,但是如果您仔细观察,您可以知道标题视图一直到表格视图的右边缘。您看不到第三个.椭圆,也几乎看不到部分标题视图后面的绿色。

我所做的一项尝试是将以下内容添加到我的表格视图控制器中:

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
        }
    }
}
4

2 回答 2

3

对于没有节索引的 UITableViews:

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

对于具有部分索引的 UITableViews:

label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    label.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
    label.trailingAnchor.constraint(equalTo: tableView.layoutMarginsGuide.trailingAnchor)
])
于 2017-10-11T21:24:48.460 回答
3

将标签添加到 tableview 后,您需要在标签中添加一些 Auto Layout 约束:

…
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.

您可以摆脱添加到viewDidLayoutSubviews.

更新:

为了好玩,我在操场上做了一些实验,发现使用layoutMarginsGuide并没有将标题标签的后沿推得足够远(我认为它在 iPhone X 上出现,但可能不是在所有设备上,或者在操场上行为有点不同)。我确实发现,对于已经存在至少一个单元格的表格视图,我可以使用aCell.contentView.bounds.width,减去表格视图的宽度并将结果除以 2,标题标签将很好地位于节索引旁边。结果,我编写了一个辅助函数来设置约束。表格视图是可选的,因此该功能可以与任何具有超级视图并需要保留在安全区域内的视图一起使用。如果传入一个表格视图,它可以有或没有节索引,但它确实需要在第 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 行的标签时,它会覆盖第一节标题和该节的第一个单元格。也需要一些滚动才能将它们从标题下方取出。将标签剪裁到一行效果很好。

于 2017-10-11T20:21:54.480 回答