如何在 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
}
我认为我需要帮助的是:
- 当我创建每个单元格时,我如何确定每个单元格是我的三种类型中的哪一种,以便我可以根据类型显示它们以及正确地使每种类型出列
- 我在每个自定义 class 中创建了
func defaultIdentifier() -> String
并在 Storyboard 中为每个单元格类型指定了重用标识符。我需要两者都做吗?
- 我是否需要注册这些单元格,或者因为我正在使用情节提要而没有必要注册这些单元格?
我发现了很多关于这个主题的线索,但它们都在 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 分配给所有控件并使它们与您的模型交互之后。
我正在创建一个视图,用于访问将在 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
}
我认为我需要帮助的是:
- 当我创建每个单元格时,我如何确定每个单元格是我的三种类型中的哪一种,以便我可以根据类型显示它们以及正确地使每种类型出列
- 我在每个自定义 class 中创建了
func defaultIdentifier() -> String
并在 Storyboard 中为每个单元格类型指定了重用标识符。我需要两者都做吗? - 我是否需要注册这些单元格,或者因为我正在使用情节提要而没有必要注册这些单元格?
我发现了很多关于这个主题的线索,但它们都在 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 分配给所有控件并使它们与您的模型交互之后。