如何在 UITableView 中使用不同的单元格样式

How do use different cell styles in a UITableView

我正在创建一个视图,用于访问将在 UITableView 中显示的应用程序中的设置。有些单元格会有 UITableViewCellAccessoryDisclosureIndicator,我需要一个有 UISwitch,另一个有 UISegmentedControl 有点像这样:

换句话说,我想我需要自定义单元格。通过大量研究,我已经非常接近了,但我无法将我学到的所有东西都结合起来一起工作。这是我所做的:

创建了三个 UITableViewCell classes:

class DisclosureCell: UITableViewCell {
  override func awakeFromNib() {
    super.awakeFromNib()
  }

  override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
  }

  class func defaultIdentifier() -> String {
    return NSStringFromClass(self)
  }

}

class SegmentedControlCell: UITableViewCell {

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

  override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
  }

 class func defaultIdentifier() -> String {
    return NSStringFromClass(self)
  }

}

class SwitchCell: UITableViewCell {

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

  override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
  }

  class func defaultIdentifier() -> String {
    return NSStringFromClass(self)
  }

}

我有我的部分 class 和部分结构,它们将提供 table 视图部分和每个可用的选择:

class SettingsData {

  func getSectionsFromData() -> [Section] {

  var settings = [Section]()

    let preferences = Section(title: "OPTIONS", objects: ["Formulas", "Lifts", "Units", "Allow 15 reps"])
    let patronFeatures = Section(title: "PATRON FEATURES", objects: ["Support OneRepMax"])
    let feedback = Section(title: "FEEDBACK", objects: ["Send Feedback", "Please Rate OneRepMax"])

    settings.append(preferences)
    settings.append(patronFeatures)
    settings.append(feedback)

    return settings
  }
}

struct Section {
  var sectionHeading: String
  var items: [String]

  init(title: String, objects: [String]) {
    sectionHeading = title
    items = objects

  }

}

最后,我的 UITableViewController:

class SettingsViewController: UITableViewController {

  override func viewDidLoad() {
    super.viewDidLoad()

    self.navigationController?.navigationBar.topItem?.title = "Settings"

    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(self.dismissSettings(_:)))

  }

  func dismissSettings(sender: AnyObject?) {
    self.dismissViewControllerAnimated(true, completion: nil)

  }

  // MARK: - Table view data source

  var sections: [Section] = SettingsData().getSectionsFromData()

  override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return sections.count

  }

  override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].items.count

  }

  override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sections[section].sectionHeading
  }

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("DisclosureCell", forIndexPath: indexPath)
    cell.textLabel?.text = sections[indexPath.section].items[indexPath.row]

    return cell

  }

我认为我需要帮助的是:

我发现了很多关于这个主题的线索,但它们都在 Objective-C and/or 中,它们没有谈到我似乎坚持的特定部分。

谢谢!

更新:

我更新了我的 override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 如下:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cellIdentifier = tableView.cellForRowAtIndexPath(indexPath)?.reuseIdentifier
    if cellIdentifier == "DisclosureCell" {
      let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "DisclosureCell")
      cell.textLabel?.text = sections[indexPath.section].items[indexPath.row]

      return cell

    } else if cellIdentifier == "SegmentedControlCell"  {
      let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "SegmentedControlCell")
      cell.textLabel?.text = sections[indexPath.section].items[indexPath.row]

      return cell
    }
      else {
          let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "SwitchCell")
          cell.textLabel?.text = sections[indexPath.section].items[indexPath.row]

      return cell
      }
  }

我希望这是朝着正确方向迈出的一步,但我仍然遗漏了一些东西,因为我收到了这个错误:

2016-07-28 07:15:35.894 One Rep Max[982:88043] 由于未捕获的异常而终止应用程序 'NSRangeException', 原因: ' -[__NSArrayI objectAtIndex:]: 索引 2 越界 [0 .. 0]'

我需要想办法让每个单元格知道它应该是三种类型中的哪一种,然后根据它是哪种类型,我可以在上面的代码中进行设置。

更新 2 我现在可以通过使用 indexPath.row:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("CustomTableViewCell", forIndexPath: indexPath) as! CustomTableViewCell
    if indexPath.row == 0 {
      cell.selectionStyle = .None
      cell.textLabel!.text = sections[indexPath.section].items[indexPath.row]
      cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
      return cell

    } else if indexPath.row == 1 {
      cell.selectionStyle = .None
      cell.textLabel!.text = sections[indexPath.section].items[indexPath.row]
      //cell.accessoryView = useAuthenticationSwitch
      let switchView: UISwitch = UISwitch()
      cell.accessoryView = switchView
      switchView.setOn(false, animated: false)
      return cell

    } else {
      cell.selectionStyle = .None
      cell.textLabel!.text = sections[indexPath.section].items[indexPath.row]
      let segmentedControl: UISegmentedControl = UISegmentedControl(items: ["lbs", "kg"])
      segmentedControl.selectedSegmentIndex = 0
      segmentedControl.addTarget(self, action: nil, forControlEvents: .ValueChanged)
      cell.accessoryView = segmentedControl
      return cell

    }
  }

问题是通过使用 indexPath.row,并不是所有的行都有正确的 accessoryView。在上面的示例中,我希望前两行具有 disclosureIndicators,第三行具有 UISegmentedControl,第四行具有 UISwitch。现在,我 完全 明白了为什么我的代码会产生这个 - 这是因为 accessoryView 是由单元格的位置决定的。相反,我希望能够在创建每个单元格时告诉它,"You're the cell for this setting, so you get a [fill in the blank] accessoryView"。我为每种类型创建了自定义单元格 classes,并尝试做我想做的事情,但无法弄清楚。您可能会注意到,在上面的代码中,我转到了一个自定义单元格 class 并重复使用了标识符。

我想我可以做 if indexPath.row == 0 | 1 { blah, blah } 之类的事情,但这种方法不会在每个 section 中都有效。如果我尝试像这样处理每个 section,那么代码将变得比现在更混乱。一定有更聪明的方法。

有吗?

我建议您对设置等屏幕使用静态单元格(不是原型)。 您可以更改故事板中的单元格类型。 在您可以将 IBOutlets 分配给所有控件并使它们与您的模型交互之后。