如何在UITableViewCell中重用UIView的xib子类

时间:2019-08-05 08:53:36

标签: ios swift uitableview uiview reusability

所以我是新手,正在尝试一些可重用性。我有一个名为SingleButtonFooterView的类,它继承了UIView的一个类,并且UI在.xib中完成。

现在我想在UITableViewCell中使用它。我已经尝试了几乎所有可能的解决方案,但对我没有用。

课程代码:

class SingleButtonFooterView: UIView {

@IBOutlet weak var button: Button50!

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

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

private func commonInit(){
    let view = UINib(nibName: "SingleButtonFooterView", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView
    view.frame = self.bounds
    self.addSubview(view)
}

override func awakeFromNib() {
    super.awakeFromNib()
    button.backgroundColor = .clear
    button.layer.cornerRadius = 5
    button.layer.masksToBounds = true

    button.titleLabel?.font = UIFont.futura(with: .medium, size: 16)
    button.setTitleColor(.white, for: .normal)
    self.contentMode = .scaleAspectFit
    self.layer.masksToBounds = true
}
}

现在cellForRowAt:

let cellId = "SingleButtonFooterView"
            var cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)

            if cell == nil {
                cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: cellId)
                let subView = SingleButtonFooterView(frame: cell.frame)

                cell.contentView.attachViewWithConstraints(subView)
                let _ = subView.viewLoadedFromNibAttached(name: cellId)
            }

            return cell

和我的VC类的viewDidLoad()中。

tableView.register(UINib(nibName: "SingleButtonFooterView", bundle: nil), forCellReuseIdentifier: "SingleButtonFooterView")

  

简而言之   -> 我想在UITableViewCell中使用UIView类(使用界面生成器-> .xib完成的UI)

3 个答案:

答案 0 :(得分:1)

如果我可以建议您做点什么,那就“按书”做。

创建一个自定义单元格,然后.xib。然后,您可以使用UIView s做任何您想做的事情(请记住,您可以创建自己的类并将其放在xib中,方法是在此处更改类:Where you change class of the UIView

在一个类中有awakeFromNibInit的情况下,某种程度上讲代码是闻起来的,因为您可以使用.xibcode来创建视图。

请记住,从VC添加子视图总是有风险的,因为您需要进行回收,这意味着除非您处理这种情况,否则该子视图可能会保留并且不被使用。

记住prepareForReuse()来处理细胞的回收。

答案 1 :(得分:0)

您在这里有两个问题:

1) Bundle.main.loadNibNamed(name, owner: self, options: nil)中的viewLoadedFromNibAttached(如果您使用与另一个问题完全相同的代码) 并且commonInit中的笔尖负载相同。 您必须决定将其放置在哪里,IMO可以摆脱

    let subView = SingleButtonFooterView(frame: cell.frame)
    cell.contentView.attachViewWithConstraints(subView)
    let _ = subView.viewLoadedFromNibAttached(name: cellId)

并将该部分放到单元格中(通过这种方式,您可以轻松维护SingleButtonFooterView的生命周期

2)猜测:xib的文件所有者为空或使用错误的类,这就是commonInitrequired init?(coder aDecoder: NSCoder)导致infinite loop的原因

编辑:

步骤1:子类UITableViewCell,我们将其称为SingleButtonCell

第2步:自定义视图(在您的情况下为SingleButtonFooterView)。注意!文件的所有者应为类本身-> SingleButtonFooterView

 @IBOutlet var contentView: UIView!

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

        loadXib()
        setup()
    }

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

        loadXib()
    }

    private func loadXib() {
        Bundle.main.loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)

        addSubview(contentView)
        contentView.frame = bounds
    }

这就是我用来从.xib加载视图的方法。 contentView是.xib文件中主视图的出口

第3步:此处有两个选择:

  • 选项3.1:(易于维护IMO)

    使用SingleButtonCell创建它自己的.xib文件

  • 3.1.1:在单元格的xib(SingleButtonCell.xib)中添加视图,并将其类更改为SingleButtonFooterView

  • 选项3.2:不要创建单元xib。而是实例化单元格中的视图(SingleButtonFooterView)并将其添加为子视图(如果需要,添加约束)。在这里,您必须小心在哪里实例化视图,因为有机会多次添加视图

答案 2 :(得分:0)

我看到的是dequeueReusableCell(withIdentifier:for:)从不返回nil。因此,您的nil-check中的代码将永远不会被调用。您可能会想到“旧” dequeueReusableCell(withIdentifier:),它可以返回nil并且可以像您一样使用。

由于它永远不会为零,因此您需要一个附加参数,说“ hasBeenInitialized”以跟踪是否已添加自定义UIView。

// In loading viewDidLoad, register cellId for type for tableView

let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)

if !hasBeenInitialized {
    // Load view from xib
    // Add view as subview to cell contentview
    // Add surrounding constraints
    hasBeenInitialized = true
}
return cell