使用自定义UITableViewCell时无法使用自定义init方法

时间:2019-01-20 19:11:30

标签: ios swift uitableview cocoa-touch

设置自定义init时,如何解决无法自定义UITableViewCell的问题?我见过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方法提及,但正如我所说,我不想删除约束和其他部分。

2 个答案:

答案 0 :(得分:3)

您尝试实现的行为实际上并不是一个好的设计,因为UITableViewCell被重用了。因此,您不应该依赖于在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
}

答案 1 :(得分:0)

由于单元格已被重新使用,并且很可能是通过dequeueReusableCell(reuseIdentifier:indexPath:)创建的,因此您通常不会在init方法中做任何特定的事情。

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

您可以在两个地方调用此函数:

  1. awakeFromNib中(如果您使用的是故事板)或init(style:reuseIdentifier:) if you aren't, to configure the cell according to the default value of textFieldStyle`
  2. 来自didSet本身的textFieldStyle观察者中。

例如

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

中配置一次单元