在尝试理解 tableView 的自定义部分 Header 中的 .layoutMarginsGuide 时感到困惑

Confused in trying to understand .layoutMarginsGuide inside custom section Header for a tableView

我正在尝试为包含 textView 的 table 视图创建自定义部分 header。我根据教程创建了一个简单的应用程序。这创建了一个工作示例。但是,当我将代码移动到我的生产应用程序时,它的布局不正确。简单的教程应用程序从 nib(没有 Main.storyboard)创建布局,生产应用程序没有。我假设这是问题的一部分。在两者中我都使用 .layoutMarginsGuide.

代码遵循自定义设计 header。

class TextViewHeader: UITableViewHeaderFooterView {
static let reuseIdentifer = "TextViewHeaderReuseIdentifier"

let sectionTextView = UITextView.init()

override public init(reuseIdentifier: String?) {
    super.init(reuseIdentifier: reuseIdentifier)

    sectionTextView.font = UIFont.preferredFont(forTextStyle: .title2)
    sectionTextView.textColor = UIColor.blue
    sectionTextView.backgroundColor = UIColor.yellow
    sectionTextView.translatesAutoresizingMaskIntoConstraints = false

    self.contentView.addSubview(sectionTextView)
    let margins = contentView.layoutMarginsGuide
    sectionTextView.isScrollEnabled = false
    //sectionTextView.text = "Something"
    sectionTextView.frameLayoutGuide.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
    sectionTextView.frameLayoutGuide.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
    sectionTextView.frameLayoutGuide.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
    sectionTextView.frameLayoutGuide.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
} 

注意布局由以下因素驱动:

 let margins = contentView.layoutMarginsGuide

为了便于跟踪 TextView 的大小和位置,我将背景设置为黄色。

  sectionTextView.backgroundColor = UIColor.yellow

需要额外的编程才能在viewDidLoad中注册header,我已经完成了:

   override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.white
    self.tableView.frame = self.view.bounds
    self.tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    self.tableView.dataSource = self
    self.tableView.delegate = self
    self.tableView.register(TextViewHeader.self, forHeaderFooterViewReuseIdentifier: TextViewHeader.reuseIdentifer)
    self.view.addSubview(self.tableView)
    self.tableView.rowHeight = UITableViewAutomaticDimension
    self.tableView.estimatedRowHeight = 300
}

并替换:

   tableView(_ tableView:, titleForHeaderInSection section:).

具有以下内容:

   func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    guard let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: TextViewHeader.reuseIdentifer) as? TextViewHeader else {
        return nil
    }
    header.customTextView.text = "Section \(section + 1)"
    return header
    }

这有效并按预期插入具有布局的 textView。

但是,当我将编程移动到我的生产应用程序时,似乎并没有发生同样的情况。在这种情况下,我将这个程序化布局与 xcode 界面构建器上的布局合并。某些东西干扰了布局。

在生产应用程序中,我在自定义 header 设计中使用了类似的代码。 (为了完整性而包含在下面)

class TextViewHeader: UITableViewHeaderFooterView {
static let reuseIdentifer = "TextViewHeaderReuseIdentifier"

let sectionTextView = UITextView.init()

override public init(reuseIdentifier: String?) {
    super.init(reuseIdentifier: reuseIdentifier)

    sectionTextView.font = UIFont.preferredFont(forTextStyle: .title2)
    sectionTextView.textColor = UIColor.blue
    sectionTextView.backgroundColor = UIColor.yellow
    sectionTextView.translatesAutoresizingMaskIntoConstraints = false

    self.contentView.addSubview(sectionTextView)
    let margins = contentView.layoutMarginsGuide
    sectionTextView.isScrollEnabled = false
    //sectionTextView.text = "Something"
    sectionTextView.frameLayoutGuide.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
    sectionTextView.frameLayoutGuide.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
    sectionTextView.frameLayoutGuide.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
    sectionTextView.frameLayoutGuide.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

这给出了以下布局。

查看故事板的 tableView 部分。我看到设置为自动的部分 Header 高度设置和设置为零的行高估计。将估计更改为自动化会更改结果:

设置:

结果header如图:

更好,但是 textView 上面的 space 太大了。

试图调查我可以在休息后看到以下内容。

-8的边距来源,-8让我很困惑。此外,这正是我从完美运行的示例中得到的结果。

但是,在此中断进行调查时,我收到以下警告:

2018-11-14 15:21:54.086637-0500 appName[31946:1780119] [LayoutConstraints] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it.

接下来列出了几个关于 leadingtrailing 但不是 top底部。因此,没有明确指出要修复的内容。

这是列出的约束条件

 "<NSLayoutConstraint:0x600002364280 UILayoutGuide:0x6000039257a0'UIScrollView-frameLayoutGuide'.leading == UILayoutGuide:0x60000397a060'UIViewLayoutMarginsGuide'.leading   (active)>",
"<NSLayoutConstraint:0x6000023642d0 UILayoutGuide:0x6000039257a0'UIScrollView-frameLayoutGuide'.trailing == UILayoutGuide:0x60000397a060'UIViewLayoutMarginsGuide'.trailing   (active)>",
"<NSLayoutConstraint:0x60000231b840 'UIView-Encapsulated-Layout-Width' _UITableViewHeaderFooterContentView:0x7fe43a815410.width == 0   (active)>",
"<NSLayoutConstraint:0x60000231b4d0 'UIView-leftMargin-guide-constraint' H:|-(8)-[UILayoutGuide:0x60000397a060'UIViewLayoutMarginsGuide'](LTR)   (active, names: '|':_UITableViewHeaderFooterContentView:0x7fe43a815410 )>",
 "<NSLayoutConstraint:0x60000231b570 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x60000397a060'UIViewLayoutMarginsGuide']-(8)-|(LTR)   (active, names: '|':_UITableViewHeaderFooterContentView:0x7fe43a815410 )>"

我唯一的想法是混合使用 "leftMargin" 和 "rightMargin" 以及“.leading”和“.trailing”。这可能是问题所在吗?但正如所讨论的那样,问题是顶部和底部对齐。

我对 table 视图和 table 视图 Header 的情节提要设置的审查没有显示有关可能冲突的更多信息。

我可能遗漏了什么?

我发现这是一种有问题的方法。 NSLayoutConstraint 问题目前超出了我 Swift 的知识范围。它似乎是由事件发生的时间驱动的。此外,有一些讨论认为它有些问题。请参阅以下内容:What is NSLayoutConstraint "UIView-Encapsulated-Layout-Height" and how should I go about forcing it to recalculate cleanly?

我决定放弃使用 tableView.dequeueReusableHeaderFooterView。部分的数量将受到限制(2 或 3,大量使用),因此成本将降至最低。

因此,我实现了一个简单的方法。

   //define size of font to use 
let sectionFont = UIFont.preferredFont(forTextStyle: .title3)
let fontsize = UIFont.preferredFont(forTextStyle: .title3).pointSize

override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let headerView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: tableView.frame.width, height: fontsize+10))
    let textView = UITextView()
    textView.frame = CGRect.init(x: 0, y: -10, width: headerView.frame.width-10, height: headerView.frame.height-0)
    textView.text = "Section \(section)"
    textView.font = sectionFont

    headerView.addSubview(textView)

    return headerView
}


override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return fontsize+10
}