Swift TableViewCell xib 没有约束

Swift TableViewCell xib doesn't have constraints

我有两个 TableView,当我设计原件时,我使用情节提要中的原型单元设计它,为了使其可重复使用,我尝试将其拉出到 .xib 中并加载那反而。但是,当它从 cellID.xib 加载时,它会在运行时失去所有约束,并且所有内容都层叠在一起。

TableViewController

let cellIdentifier = "cellID"
override func viewDidLoad() {
    super.viewDidLoad()

    tableView.register(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 300
}

情节提要中的原型单元格(曾经有效)

复制粘贴到 XIB 时的单元格

约束

XIB 视图层次结构

好像是单元格高度的问题吧?因此,约束无法正常工作。

当你使用 XIB files:

时你需要这个覆盖函数
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
            return 300
}

但是你的约束一定是错误的,或者说它们并不完美。我知道他们正在使用故事板中的原型单元,但这并不能使它们 100% 完美地工作,对吗? 你的 UIImageView 没有 heightwidth。你应该尝试用一些约束来设置它。 (或者您设置 width 并使用 Aspect Ratio 约束)

问题

在您的问题标题中,您询问了如何解决 "Swift TableViewCell xib doesn't have constraints." 此外,在赏金中,您指定的答案应该是:

An adequate answer showing why constraints are lost when moved to a xib, when they exist in the xib, and how to address this problem.

据我了解,您的问题分为两部分:

  1. 自定义 TableViewCell xib 没有约束的问题
  2. 为什么当 copy/pasted 从 Storyboard 原型到 xib 时约束丢失

对于问题 #1,我使用了与您在自定义单元格 xib 的屏幕截图中显示的几乎所有相同的约束,并且它有效。我会在下面详细解释。

对于问题 #2,我发现约束没有丢失。您可能需要共享您的项目,以便其他人可以复制您遇到的问题。我 copy/pasted 一个 Storyboard 原型单元与 xib 具有类似的约束,我没有任何约束问题。所以我可以确认 copy/paste 功能确实有效。

解决方案演示

我创建了以下演示来测试您的问题。请参阅下面的屏幕截图。 tableView 包含六个单元格。第 1 个和第 2 个相同,并且具有重用标识符 MyCell。第 3 个和第 4 个相同,并且具有重用标识符 MyCopyPasteCell。第 5 个和第 6 个相同,并且具有重用标识符 MyPrototypeCell

MyCell 存在于 xib 中并使用几乎所有与您在屏幕截图中显示的相同的约束。如您所见,不存在约束问题。 MyCopyPasteCell 使用类似的约束并且 copy/pasted 从 Storyboard 原型到 xib。 MyPrototypeCell是复制过来的原型。这最后四个单元格看起来完全一样,即使原型被复制到 xib。约束从原型转移到 xib 没有问题。

约束

在下面的代码中,我列出了您在 ContentView 屏幕截图中显示的所有约束。 (请注意,我还实现了 height=20aspect=1:1height=75 约束,尽管它们没有在下面列出。)两个约束被注释掉了,因为我没有使用它们。我还添加了一个约束来替换另一个未使用的约束。

// bottomMargin = Profile Image View.bottom + 188.5
bottomMargin = Profile Image.bottom + 17
Profile Image View.top = Username Label.top
Profile Image View.leading = leadingMargin + 2
Profile Image View.top = topMargin + 20
Username Label.leading = Content Text View.leading    
// Username Label.top = topMargin + 20        
Username Label.trailing = Content Text View.trailing
Username Label.leading = Profile Image View.trailing + 15
trailingMargin = Username Label.trailing + 10
Content Text View.top = Username Label.bottom + 5
Content Text View.leading = leadingMargin + 92
bottomMargin = Content Text View.bottom + 20

第一个注释约束 // bottomMargin = Profile Image View.bottom + 188.5 没有意义,因为它将图像底部与单元格底部分开 188.5。这也不符合您在 Storyboard 中的 Prototype cell (Used to work) 屏幕截图。我将其替换为 bottomMargin = Profile Image.bottom + 17,这只是将 188.5 替换为 17.

第二个注释约束 // Username Label.top = topMargin + 20(用 20 分隔用户名和 topMargin)在技术上可以工作。但是,它的功能对于 Profile Image.top = topMargin + 20(将个人资料图片和 topMargin 相隔 20)和 Profile Image View.top = Username Label.top(将个人资料图片和用户名设置为相同的顶部分隔,即相隔 20)是多余的。

MyTableViewController

以下是我的视图控制器。基本上我创建了三个部分,每个部分有两个 cells/rows。 MyCellMyCopyPasteTableViewCell 来自 xib,并在 viewDidLoad() 中注册。 MyPrototypeCell 来自 Storyboard,未在 viewDidLoad() 中注册。

//  MyTableViewController.swift
import UIKit    
class MyTableViewController: UITableViewController {

    let myCell = "MyCell"
    let myCopyPasteCell = "MyCopyPasteTableViewCell"
    let myPrototypeCell = "MyPrototypeCell"

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UINib(nibName: myCell, bundle: nil), forCellReuseIdentifier: myCell)
        tableView.register(UINib(nibName: myCopyPasteCell, bundle: nil), forCellReuseIdentifier: myCopyPasteCell)
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 300
    }

    // MARK: - Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: myCell, for: indexPath)
            return cell
        } else if indexPath.section == 1 {
            let cell = tableView.dequeueReusableCell(withIdentifier: myCopyPasteCell, for: indexPath)
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: myPrototypeCell, for: indexPath)
            return cell
        }
    }
}

Github link

https://github.com/starkindustries/TableViewCellConstraintsTest

问题与解决方案

您可能已禁用 XIB 的 Autolayout 以打开它 ON 从右上角菜单转到 File Inspector

您可以按照简单的步骤从 Xib 创建单元格

1. Create UITableCell with .xib ( ✅ 同时创建 Xib 文件)

2.给出小区标识符

3.布局约束

ImageView 给出来自 TopLeftBottom 的对比 高度常量和纵横比[我设置了边框以显示框架]

UIlable for title lable 从三个方面给约束 来自 TopLeftRight NumberOflines=0 (不要给出高度常量 - ⚠️ 如果给出警告,请继续并更新约束)

UIlable 对于 Descriptions lable 也从所有四个方面给出约束 NumberOflines=0 (⚠️这会给你一个错误去建议和改变UIlable约束的优先级)

见下方截图

更改优先级 比再次更新约束

4.代码在UIViewController

 @IBOutlet var tableView: UITableView!

    var cellIdentifier="cell"
    var cellXibName = "MyTableCell"


    override func viewDidLoad() {
        super.viewDidLoad()


        tableView.register(UINib(nibName: cellXibName, bundle: nil), forCellReuseIdentifier: cellIdentifier)
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 320


    }



    func numberOfSections(in tableView1: UITableView) -> Int {
        return 3
    }

     func tableView(_ tableView1: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

            let cell :MyTableCell = tableView1.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! MyTableCell


            return cell
    }

最后输出如你所愿

输出

我希望这对你有用......如果这对你有用,请告诉我。

解决方案:

我已找到您问题的解决方案。希望对您有所帮助

我用uiview裁剪所有单元格元素。

和细胞设计

代码:

class ViewController: UIViewController {

@IBOutlet var tableView: UITableView!



 override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.estimatedRowHeight = 100
        self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.register(UINib(nibName: "TestCell", bundle: Bundle.main), forCellReuseIdentifier: "TestCell")

        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

extension ViewController : UITableViewDataSource, UITableViewDelegate {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1;
    }

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

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

        cell.selectionStyle = .none

        return cell
    }

}

结果: