【问题标题】:How to Re-use an xib subclass of UIView in UITableViewCell如何在 UITableViewCell 中重用 UIView 的 xib 子类
【发布时间】:2019-12-12 18:34:12
【问题描述】:

所以我是一个新手,正在尝试一些可重用性。我有一个名为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 类(使用界面生成器完成的 UI -> .xib)

【问题讨论】:

  • attachViewWithConstraints 中的内容是什么
  • 是的,我忘了添加那个 sn-p 事实上我会从我一直在寻求帮助的地方分享 SO 答案,它基本上有所有的 sn-ps,stackoverflow.com/questions/41851892/…
  • 感谢@ElTomato 的评论,但在我的情况下tableview 渲染是通过编程方式完成的。您分享的帖子也与我提出的问题不符。 =)

标签: ios swift uitableview uiview reusability


【解决方案1】:

如果我能建议你做点什么,那就“按部就班”去做吧。

创建一个自定义单元格和.xib。然后你可以用UIViews 做任何你想做的事(记住你可以创建你自己的类并通过在此处更改类将其放入xib:

awakeFromNibInit 放在一个类中,这在某种程度上是一种代码异味,因为您使用.xibcode 来创建视图。

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

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

【讨论】:

  • 其实我已经在.xib 中设计了UI,它继承自UIView。现在按照产品的UI来看,.xib中的UI基本上也用在了其他一些屏幕上。现在很明显,既然我已经设计了它,为什么还要重新设计它。?另一个屏幕有一个UITableView...
  • @YashBedi 你能改写你的评论吗?很难理解
  • 好的,我这样说吧。我想在 UITableViewCell 中使用 UIView 类(使用界面生成器完成的 UI -> .xib)。
  • @YashBedi 我上面的帖子回答了你的问题。同样,在.xib 中创建一个简单的 UIView 并将其附加到单元格。接下来,更改您附加到单元格的 UIView 的类,它已准备就绪。只是不要使用从笔尖唤醒的方法。它将从required init?(coder aDecoder: NSCoder) 使用,这是后续:stackoverflow.com/questions/38386339/…
  • 非常感谢您抽出时间来写答案。但它根本没有回答我的问题。最重要的是,您的解释非常模糊,例如-> Then you can do whatever you want with the...如果您可以编写一个可行的解决方案,或者您认为您的代码可以运行,或者您真的知道 SO 上提出的问题的答案,那么您应该发布您的答案,否则总是更喜欢 cmets。跨度>
【解决方案2】:

这里有两个问题:

1) Bundle.main.loadNibNamed(name, owner: self, options: nil) in 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)并将其添加为子视图(如果需要,添加约束)。在这里你必须小心在哪里实例化视图,因为有机会多次添加它

【讨论】:

  • 在上述所有之前,你能建议我应该如何为它注册单元格。
【解决方案3】:

我可以看到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

【讨论】:

  • 谢谢 Sunkas,我会尝试解决方案并会在这里更新,再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 2017-09-24
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 2013-08-26
  • 2015-11-27
相关资源
最近更新 更多