如何使用 Swift 在 UITableViewCell 中设置 customView

How to set customView in UITableViewCell with Swift

我有 UITableView、UITablaViewCell、CustomView

并且 UITableViewCell 包含 customView。

我正在尝试使用我的函数而不是 cellForRowAt 将 Product 的数据放入单元格。

单元格仅显示原始视图 ProductView.xib,数据为空

请帮忙。

ViewController.swift

struct Product {
    let brand: String
    let product: String
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! ProductTableViewCell
    // this line is not work
    // productView is not update
    cell.productView = createProductView(product: product)
    return cell
}
    
func createProductView(product: Product) -> ProductView {
    let productView = ProductView()
    productView.brandLabel.text = product.brand
    productView.productLabel.text = product.product
    return productView
}

UITableViewCell.swift

class ProductTableViewCell: UITableViewCell {
    @IBOutlet var productView: ProductView!
}

ProductView.swift

class ProductView: UIView {

@IBOutlet weak var productView: UIView!
@IBOutlet weak var brandLabel: UILabel!
@IBOutlet weak var productLabel: UILabel!

override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
}

private func commonInit(){
    let bundle = Bundle(for: ProductView.self)
    bundle.loadNibNamed("ProductView", owner: self, options: nil)
    addSubview(productView)
    productView.frame = self.bounds
}

您的代码存在多个问题

问题 1: cellForRowAt IndexPath 被多次调用,使用您的代码,每次滚动 tableView(单元格)时,您最终都会创建一个新的 ProductView被重复使用)。相反,您只能创建一次产品视图并在每次重复使用单元格时更新其标签

问题 2:ProductView 的 commonInit 中,您使用 productView.frame = self.bounds 设置框架 self.bounds 将始终为 (0,0, 0,0).因为您已将 ProductView 实例化为 ProductView()

问题 3: createProductView 应该是 return ProductView 的实例,因此方法签名无效,因此您应该更改它从 func createProductView(product: Product) -> ProductView()func createProductView(product: Product) -> ProductView 正如上面的回答中已经建议的那样

有什么更好的解决方案?

class ProductTableViewCell: UITableViewCell {
    var productView: ProductView!

    func updateProductView(product: Product) {
        productView.brandLabel.text = product.brand
        productView.productLabel.text = product.product
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        productView.brandLabel.text = nil
        productView.productLabel.text = nil
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        self.productView = createProductView()
        self.addSubview(self.productView)
        self.productView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            self.productView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
            self.productView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
            self.productView.topAnchor.constraint(equalTo: self.topAnchor),
            self.productView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        ])
    }


    func createProductView() -> ProductView {
        return ProductView()
    }
}

终于在你的cellForRowAtIndexPath

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

    //assuming you already have a product for index path
    cell.updateProductView(product: product)
    return cell
}

编辑:

由于 OP 在从包中加载 nib 时遇到问题,请在此处更新答案。

在你的 ProductView common init 中改变你访问 bundle 的方式 Bundle(for: ProductView.self)Bundle.main如下图

class ProductView: UIView {

@IBOutlet weak var productView: UIView!
@IBOutlet weak var brandLabel: UILabel!
@IBOutlet weak var productLabel: UILabel!

override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    commonInit()
}

private func commonInit(){
    Bundle.main.loadNibNamed("ProductView", owner: self, options: nil)
    addSubview(productView)
}

需要注意的事项

  1. 确保您的包中有一个名为 ProductView 的 XIB
  2. 确保您已将其文件所有者设置为 ProductView