【问题标题】:Working around not having a custom init method when using a custom UITableViewCell解决使用自定义 UITableViewCell 时没有自定义 init 方法的问题
【发布时间】:2019-06-14 06:06:38
【问题描述】:

当我设置自定义 UITableViewCell 时,如何解决无法使用自定义 init 方法的问题?我见过How can I use a custom initializer on a UITableViewCell?,但是,我正在添加我想在init 方法中覆盖的约束。我需要添加一个格式不同的文本字段,例如数字。

我尝试从UITableViewCell 类继承并在init 方法中设置样式枚举,但在调用super.init 之前无法设置。

class LabelIntegerTextfieldTableViewCell: LabelTextfieldTableViewCell {

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
    {
        super.textFieldStyle = .Integer
// 'self' used in property access 'textFieldStyle' before 'super.init' call

        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
open class LabelTextfieldTableViewCell: UITableViewCell
{
    public var label = UILabel()
    public var textField = UITextField()
    public var textFieldStyle = eTextfieldStyle.Integer

    override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
    {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        switch textFieldStyle
        {
        case .Integer:
            textField.contentVerticalAlignment = .center
            textField.textAlignment = .right
            textField.keyboardType = .numberPad
// snip

        if (textFieldStyle == .MediumText)
        {
            contentView.addConstraints(NSLayoutConstraint
              .constraints(withVisualFormat: 
              "H:|-[label]-[textField(==label)]-|", 
              options: [], metrics: nil, views: viewsDict))
        }
        else
        {
            contentView.addConstraints(NSLayoutConstraint
              .constraints(withVisualFormat: 
              "H:|-[label]-[textField(100)]-|", 
              options: [], metrics: nil, views: viewsDict))
        }

我知道在其他 SO 帖子中提到使用 update 方法,但正如我所说,我宁愿不删除约束和其他部分。

【问题讨论】:

  • 您是否尝试过使用便利初始化?
  • 单元被重复使用,因此无论如何您都需要重新配置单元约束。您可以在 textFieldStyle 属性上使用 didSet 观察者。
  • 感谢@Let's_Create,但我在使用 convince init 时遇到了同样的问题,在超级调用 init 之前仍然无法使用它。

标签: ios swift uitableview cocoa-touch


【解决方案1】:

您试图实现的行为实际上并不是一个好的设计,因为UITableViewCells 被重用了。所以你不应该依赖于在init 方法中配置它们的外观。例如,您可以实例化一个传递Integer 样式的单元格,然后,如果您将单元格设置为具有不同的样式,您将获得不一致的状态(因为您将看到的内容不会反映您设置的内容)。话虽如此,您应该考虑使用更具反应性的方法,您的单元格的行为根据设置的内容,无论何时设置。在您的情况下,您可能想查看didSet 属性观察者。你会有类似下面的东西:

public var textFieldStyle = eTextfieldStyle.Integer {
  didSet {
    updateAppearance()
  }
}

func updateAppearance() {
  switch textFieldStyle {
    case .Integer:
      // ...
  }
}

编辑

而在您的tableView(_:cellForRowAt:) 中,您只需要设置正确的样式,如下所示:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "your cell identifier goes here", for: indexPath)

  // Here you obtain the proper style depending on the index path, for instance:
  if indexPath.row == 0 {
    cell.textFieldStyle = .Integer
  } else {
    cell.textFieldStyle = . MediumText
  }
  return cell
}

【讨论】:

  • 你能提供一些cellForRowAt方法的实现代码吗?我不确定是否应该在我的 init 方法中提供我的约束,或者在 updatrAppearance 中提供唯一的约束
【解决方案2】:

由于单元格被重复使用并且很可能通过dequeueReusableCell(reuseIdentifier:indexPath:) 创建,因此您通常不会在init 方法中执行任何特定操作。

在您的情况下,我建议您创建一个基于 textFieldStyle 属性配置单元格的函数(删除任何以前的配置,例如必要时的约束;这可能意味着您需要保留对这些约束的引用在属性中)。

你可以在两个地方调用这个函数:

  1. awakeFromNib(如果您使用情节提要)或init(style:reuseIdentifier:) if you aren't, to configure the cell according to the default value oftextFieldStyle`
  2. 在来自textFieldStyle 本身的didSet 观察者中。

例如

open class LabelTextfieldTableViewCell: UITableViewCell
{
    public var label = UILabel()
    public var textField = UITextField()
    public var textFieldStyle = eTextfieldStyle.Integer {
       didSet {
           self.configureCell()
       }
    }

    override public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
{
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.configureCell()
    }

    override func awakeFromNib() {
         super.awakeFromNib()
         self.configureCell()
    }

    private func configureCell() {


        switch textFieldStyle {
        case .Integer:
            textField.contentVerticalAlignment = .center
            textField.textAlignment = .right
            textField.keyboardType = .numberPad
// snip

        if (textFieldStyle == .MediumText)
        {
            contentView.addConstraints(NSLayoutConstraint
          .constraints(withVisualFormat: 
          "H:|-[label]-[textField(==label)]-|", 
          options: [], metrics: nil, views: viewsDict))
        }
        else
        {
            contentView.addConstraints(NSLayoutConstraint
          .constraints(withVisualFormat: 
          "H:|-[label]-[textField(100)]-|", 
          options: [], metrics: nil, views: viewsDict))
        }

在您的cellForRow(at:) 中,您只需将一个可重复使用的单元格出列并设置其类型:

    cell.textFieldStyle = .MediumText

另一种方法是创建三个不同的子类并将它们与不同的重用标识符相关联。然后你可以在awakeFromNib/init中配置一次单元格

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-04
    • 2013-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 1970-01-01
    相关资源
    最近更新 更多