在表格视图中放置不同的自定义单元格类型
Putting different custom cell types in a tableview
我在尝试用不同的自定义单元格类型填充单个表格视图时遇到了问题。我试图删除代码中所有不相关的部分。我可能有很多后续问题,但在 dequereusablecell 语句(在 cellforrow 函数中)中,我无法将单元格向下转换为存储在数组 cellTypes 中的 FilterTableViewCell 或 FilterTableViewCell2 类型
.我收到错误 "Array types are now written with the brackets around the element type"...它认为我正在尝试向下转换为数组类型,而不是数组 cellTypes 的给定索引中的单元格类型。我希望这很清楚。
我也曾尝试在 switch 语句的每种情况下放置一个 dequereusablecell 语句,但我在代码的其他部分出现错误。它基本上将 FIlterTableViewCell 和 FilterTableViewCell2 视为基类类型 (UITableViewCell),因此无法访问这两个子类中的属性。我希望这很清楚。但如果您发现我代码的其他部分有任何问题(尤其是我使用数组的方式),请告诉我。
代码:
import Foundation
import UIKit
class FilterViewController: UIViewController, UITableViewDelegate,UITableViewDataSource, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate,UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
let properties = ["Diet","Body Type","Looking For","Ethnicity"]
var values:NSArray!
let dietOpts:NSArray = ["Vegan","Plant-based","Vegetarian","Meat Eater"]
let bodytypeOpts:NSArray = ["Muscular","Athletic","Lean","Husky","Chubby","Large","Fat"]
let lookingforOpts:NSArray = ["Friends","Dates","Chat","Networking","Relationship","Right Now"]
let ethnicityOpts:NSArray = ["Hispanic/Latino","Black","White","Middle Eastern","South Asian","Asian","Native American","Pacific Islander"]
var userFilterTable : UITableView!
var cellTypes = [FilterTableViewCell.self,FilterTableViewCell.self,FilterTableViewCell2.self,FilterTableViewCell2.self]
var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),FilterTableViewCell2(),FilterTableViewCell2()]
let cellIDs = ["cellId","cellId","cellId2","cellId2"]
var toolBar : UIToolbar!
var i:Int!
var myUIPicker = UIPickerView()
var multiplePicker = MultiplePicker()
var myValues: NSArray!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.blue
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
userFilterTable = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
userFilterTable.register(FilterTableViewCell.self, forCellReuseIdentifier: "cellId")
userFilterTable.register(FilterTableViewCell2.self, forCellReuseIdentifier: "cellId2")
userFilterTable.backgroundColor = UIColor.clear
userFilterTable.isScrollEnabled = false
userFilterTable.delegate = self
userFilterTable.dataSource = self
userFilterTable.rowHeight = 40
self.userFilterTable.reloadData()
self.view.addSubview(userFilterTable)
}
@objc func buttonAction(_ sender: UIButton!){
print("Button tapped")
}
func generalPicker(){
myUIPicker.becomeFirstResponder()
self.myUIPicker.delegate = self
self.myUIPicker.dataSource = self
}
@objc func donePicker() {
reminderCells[i].valueTextField.resignFirstResponder()
}
func doMultiplePicker(){
multiplePicker.becomeFirstResponder()
//multiplePicker.delegate = self
//multiplePicker.dataSource = self
reminderCells[i].valueTextField.backgroundColor = UIColor.white
toolBar = UIToolbar()
toolBar.sizeToFit()
}
@objc func donePicker2() {
reminderCells[i].valueTextField.text = multiplePicker.str
reminderCells[i].valueTextField.resignFirstResponder()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
reminderCells[indexPath.row].valueTextField.becomeFirstResponder()
i = indexPath.row
print(properties[indexPath.item]) //print("Diet")
switch properties[indexPath.item] {
case "Diet":
myValues = dietOpts
generalPicker()
case "BodyType":
myValues = bodytypeOpts
generalPicker()
case "Looking For":
myValues = lookingforOpts
generalPicker()
case "Ethnicity":
myValues = bodytypeOpts
doMultiplePicker()
default:
print("Some other character")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// retuen no of rows in sections
return properties.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(indexPath.row)
let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! cellTypes[indexPath.row]
switch properties[indexPath.item]{
case "Diet","Body Type":
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = myUIPicker
case "Looking For","Ethnicity":
multiplePicker.frame = CGRect(x: 0, y: 0, width: 100, height: 300)
multiplePicker.myValues = ethnicityOpts as! [String]
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker2))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = multiplePicker
default:
print("default")
}
cell.backgroundColor = UIColor.clear
cell.property.text = properties[indexPath.item]
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
cell.valueTextField.tag = indexPath.item
toolBar = UIToolbar()
toolBar.sizeToFit()
reminderCells[indexPath.item] = cell
return cell
}
// data method to return the number of column shown in the picker.
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
// data method to return the number of row shown in the picker.
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print(myValues.count)
return myValues.count
}
// delegate method to return the value shown in the picker
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return myValues[row] as? String
}
// delegate method called when the row was selected.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
reminderCells[i].valueTextField.text = myValues[row] as? String
}
}
在 Matt 的回复后对 cellForRowAt 进行编辑(这次我在编译时指定类型):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch properties[indexPath.item]{
case "Diet","Body Type":
let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! FilterTableViewCell
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = myUIPicker
cell.backgroundColor = UIColor.clear
cell.property.text = properties[indexPath.item]
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
cell.valueTextField.tag = indexPath.item
toolBar = UIToolbar()
toolBar.sizeToFit()
reminderCells[indexPath.item] = cell
return cell
case "Looking For","Ethnicity":
let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! FilterTableViewCell2
multiplePicker.frame = CGRect(x: 0, y: 0, width: 100, height: 300)
multiplePicker.myValues = ethnicityOpts as! [String]
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker2))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = multiplePicker
cell.backgroundColor = UIColor.clear
cell.property.text = properties[indexPath.item]
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
cell.valueTextField.tag = indexPath.item
toolBar = UIToolbar()
toolBar.sizeToFit()
reminderCells[indexPath.item] = cell
return cell
default:
print("default")
}
您在 cellForRowAt
中的 dequeue
电话中提出的这个想法巧妙而自然,但却是非法的:
as! cellTypes[indexPath.row]
Swift 不会让您将 (as!
) 转换为直到运行时才指定的类型。它是一种静态语言,而不是动态语言。类型必须是编译时指定的文字类型。
您只需要将 cellForRowAt
实现分成两个完全独立的切换案例,一个用于第 0 行和第 1 行,一个用于第 2 行和第 3 行,然后执行不同的 dequeue
对于每一个,每一个都声明并指定了自己的本地 cell
变量,并使用强制转换 as! FilterTableViewCell
或 as! FilterTableViewCell2
字面意思 — 然后从那里开始,分别,在每个案例中。
您不能像您的外观优雅的代码尝试那样统一这两种情况,因为只有在 cell
被键入 字面 的上下文中,如 FilterTableViewCell 或 FilterTableViewCell2 可以您访问属于相应类型的属性。
至于这个表达式:
var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),
FilterTableViewCell2(),FilterTableViewCell2()]
...这里的问题是 Swift 只能推断这一定是一个没有 FilterTableViewCell 属性的 UITableViewCell 数组。
您可以通过定义第三种类型来解决这个问题,例如FilterTableViewCellParent,充当 FilterTableViewCell 和 FilterTableViewCell2 的公共超类,并赋予 it 它们可以继承的共同属性; reminderCells
然后可以是 FilterTableViewCellParent 的数组,您将能够通过它的元素访问属性。 (或者当然,您可以将 FilterTableViewCell 设为 FilterTableViewCell2 的超类,或者 反之亦然,因此只使用两种类型。)
但我个人认为你应该放弃成为 "elegant" 的尝试,在两种切换情况下完全分开做所有事情,即使以重复为代价。有时必须像超人穿裤子一样编程;他可能是超人,但他仍然必须一次进入一条腿。
我在尝试用不同的自定义单元格类型填充单个表格视图时遇到了问题。我试图删除代码中所有不相关的部分。我可能有很多后续问题,但在 dequereusablecell 语句(在 cellforrow 函数中)中,我无法将单元格向下转换为存储在数组 cellTypes 中的 FilterTableViewCell 或 FilterTableViewCell2 类型 .我收到错误 "Array types are now written with the brackets around the element type"...它认为我正在尝试向下转换为数组类型,而不是数组 cellTypes 的给定索引中的单元格类型。我希望这很清楚。
我也曾尝试在 switch 语句的每种情况下放置一个 dequereusablecell 语句,但我在代码的其他部分出现错误。它基本上将 FIlterTableViewCell 和 FilterTableViewCell2 视为基类类型 (UITableViewCell),因此无法访问这两个子类中的属性。我希望这很清楚。但如果您发现我代码的其他部分有任何问题(尤其是我使用数组的方式),请告诉我。
代码:
import Foundation
import UIKit
class FilterViewController: UIViewController, UITableViewDelegate,UITableViewDataSource, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate,UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate{
let properties = ["Diet","Body Type","Looking For","Ethnicity"]
var values:NSArray!
let dietOpts:NSArray = ["Vegan","Plant-based","Vegetarian","Meat Eater"]
let bodytypeOpts:NSArray = ["Muscular","Athletic","Lean","Husky","Chubby","Large","Fat"]
let lookingforOpts:NSArray = ["Friends","Dates","Chat","Networking","Relationship","Right Now"]
let ethnicityOpts:NSArray = ["Hispanic/Latino","Black","White","Middle Eastern","South Asian","Asian","Native American","Pacific Islander"]
var userFilterTable : UITableView!
var cellTypes = [FilterTableViewCell.self,FilterTableViewCell.self,FilterTableViewCell2.self,FilterTableViewCell2.self]
var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),FilterTableViewCell2(),FilterTableViewCell2()]
let cellIDs = ["cellId","cellId","cellId2","cellId2"]
var toolBar : UIToolbar!
var i:Int!
var myUIPicker = UIPickerView()
var multiplePicker = MultiplePicker()
var myValues: NSArray!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.blue
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
userFilterTable = UITableView(frame: CGRect(x: 0, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
userFilterTable.register(FilterTableViewCell.self, forCellReuseIdentifier: "cellId")
userFilterTable.register(FilterTableViewCell2.self, forCellReuseIdentifier: "cellId2")
userFilterTable.backgroundColor = UIColor.clear
userFilterTable.isScrollEnabled = false
userFilterTable.delegate = self
userFilterTable.dataSource = self
userFilterTable.rowHeight = 40
self.userFilterTable.reloadData()
self.view.addSubview(userFilterTable)
}
@objc func buttonAction(_ sender: UIButton!){
print("Button tapped")
}
func generalPicker(){
myUIPicker.becomeFirstResponder()
self.myUIPicker.delegate = self
self.myUIPicker.dataSource = self
}
@objc func donePicker() {
reminderCells[i].valueTextField.resignFirstResponder()
}
func doMultiplePicker(){
multiplePicker.becomeFirstResponder()
//multiplePicker.delegate = self
//multiplePicker.dataSource = self
reminderCells[i].valueTextField.backgroundColor = UIColor.white
toolBar = UIToolbar()
toolBar.sizeToFit()
}
@objc func donePicker2() {
reminderCells[i].valueTextField.text = multiplePicker.str
reminderCells[i].valueTextField.resignFirstResponder()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
reminderCells[indexPath.row].valueTextField.becomeFirstResponder()
i = indexPath.row
print(properties[indexPath.item]) //print("Diet")
switch properties[indexPath.item] {
case "Diet":
myValues = dietOpts
generalPicker()
case "BodyType":
myValues = bodytypeOpts
generalPicker()
case "Looking For":
myValues = lookingforOpts
generalPicker()
case "Ethnicity":
myValues = bodytypeOpts
doMultiplePicker()
default:
print("Some other character")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// retuen no of rows in sections
return properties.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print(indexPath.row)
let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! cellTypes[indexPath.row]
switch properties[indexPath.item]{
case "Diet","Body Type":
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = myUIPicker
case "Looking For","Ethnicity":
multiplePicker.frame = CGRect(x: 0, y: 0, width: 100, height: 300)
multiplePicker.myValues = ethnicityOpts as! [String]
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker2))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = multiplePicker
default:
print("default")
}
cell.backgroundColor = UIColor.clear
cell.property.text = properties[indexPath.item]
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
cell.valueTextField.tag = indexPath.item
toolBar = UIToolbar()
toolBar.sizeToFit()
reminderCells[indexPath.item] = cell
return cell
}
// data method to return the number of column shown in the picker.
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
// data method to return the number of row shown in the picker.
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
print(myValues.count)
return myValues.count
}
// delegate method to return the value shown in the picker
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return myValues[row] as? String
}
// delegate method called when the row was selected.
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
reminderCells[i].valueTextField.text = myValues[row] as? String
}
}
在 Matt 的回复后对 cellForRowAt 进行编辑(这次我在编译时指定类型):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch properties[indexPath.item]{
case "Diet","Body Type":
let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! FilterTableViewCell
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = myUIPicker
cell.backgroundColor = UIColor.clear
cell.property.text = properties[indexPath.item]
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
cell.valueTextField.tag = indexPath.item
toolBar = UIToolbar()
toolBar.sizeToFit()
reminderCells[indexPath.item] = cell
return cell
case "Looking For","Ethnicity":
let cell = tableView.dequeueReusableCell(withIdentifier: cellIDs[indexPath.row], for: indexPath) as! FilterTableViewCell2
multiplePicker.frame = CGRect(x: 0, y: 0, width: 100, height: 300)
multiplePicker.myValues = ethnicityOpts as! [String]
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(donePicker2))
toolBar.setItems([doneButton], animated: false)
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = multiplePicker
cell.backgroundColor = UIColor.clear
cell.property.text = properties[indexPath.item]
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
cell.valueTextField.tag = indexPath.item
toolBar = UIToolbar()
toolBar.sizeToFit()
reminderCells[indexPath.item] = cell
return cell
default:
print("default")
}
您在 cellForRowAt
中的 dequeue
电话中提出的这个想法巧妙而自然,但却是非法的:
as! cellTypes[indexPath.row]
Swift 不会让您将 (as!
) 转换为直到运行时才指定的类型。它是一种静态语言,而不是动态语言。类型必须是编译时指定的文字类型。
您只需要将 cellForRowAt
实现分成两个完全独立的切换案例,一个用于第 0 行和第 1 行,一个用于第 2 行和第 3 行,然后执行不同的 dequeue
对于每一个,每一个都声明并指定了自己的本地 cell
变量,并使用强制转换 as! FilterTableViewCell
或 as! FilterTableViewCell2
字面意思 — 然后从那里开始,分别,在每个案例中。
您不能像您的外观优雅的代码尝试那样统一这两种情况,因为只有在 cell
被键入 字面 的上下文中,如 FilterTableViewCell 或 FilterTableViewCell2 可以您访问属于相应类型的属性。
至于这个表达式:
var reminderCells = [FilterTableViewCell(),FilterTableViewCell(),
FilterTableViewCell2(),FilterTableViewCell2()]
...这里的问题是 Swift 只能推断这一定是一个没有 FilterTableViewCell 属性的 UITableViewCell 数组。
您可以通过定义第三种类型来解决这个问题,例如FilterTableViewCellParent,充当 FilterTableViewCell 和 FilterTableViewCell2 的公共超类,并赋予 it 它们可以继承的共同属性; reminderCells
然后可以是 FilterTableViewCellParent 的数组,您将能够通过它的元素访问属性。 (或者当然,您可以将 FilterTableViewCell 设为 FilterTableViewCell2 的超类,或者 反之亦然,因此只使用两种类型。)
但我个人认为你应该放弃成为 "elegant" 的尝试,在两种切换情况下完全分开做所有事情,即使以重复为代价。有时必须像超人穿裤子一样编程;他可能是超人,但他仍然必须一次进入一条腿。