如何使用 Swift 在 UITableViewCell 中设置 customView

问题描述

我有 UITableView、UITablaViewCell、CustomView

和 UITableViewCell 包括 customView。

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

单元格仅显示带有空数据的原始视图 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 will always be(0,0) 设置框架。因为您已将 ProductView 实例化为 ProductView()

问题 3: createProductView 应该返回 ProductView 的实例,因此方法签名无效,因此您应该将其从 func createProductView(product: Product) -> ProductView() 更改为 {{ 1}} 正如上面的回答中已经建议的

什么是更好的解决方案?

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

编辑:

由于 OP 面临从包中加载笔尖的问题,请在此处更新答案。

在您的 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 } common init 中更改您访问 bundle 的方式 ProductViewBundle(for: ProductView.self) 如下图

Bundle.main

需要注意的事项

  1. 确保您的捆绑包中有一个名为 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) } 的 XIB
  2. 确保您已将其文件所有者设置为 ProductView