如何调整UITableView tableHeaderView的左右内嵌或边距?

时间:2017-10-11 19:43:12

标签: ios uitableview uiedgeinsets

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

波泰特:

enter image description here

风景:

enter image description here

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

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

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

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

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

2 个答案:

答案 0 :(得分:2)

对于没有部分索引的UITableViews:

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

对于带有节索引的UITableView:

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

答案 1 :(得分:1)

在将其添加到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

您可以删除添加到viewDidLayoutSubviews的代码。

更新

为了好玩,我在操场上做了一些实验,发现使用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行的标签时,它将覆盖第一部分标题和该部分的第一个单元格。它需要一些滚动才能将它们从标题下方取出。将标签剪切成一行虽然效果很好。