UITableview with more than One Custom Cells with Swift

I want to use a UITableview with different custom tableViewCells. My 3 cells are as such:

  • Cell1: should have an image and a label.
  • Cell2: should have two labels.
  • Cell3: should have a dayPicker.

I don't want to code a tag for the cells. How can I manage this in Swift. Do I have to code my own class for every cell? Can I use one tableviewController? How can I populate data in different cells?

I would like to generate a tableView, like a contact app of an iOS device.

109646 次浏览

UITableViewController继承的 UIViewController本身已经映射了 UITableviewDataSourceUITableviewDelegate

您可以在 ViewController中继承 UITableViewController或使用 TableView。 之后,您必须实现在 UITableviewDataSource中声明的所需方法(cellForRowAtIndexPath and numberOfRowsInSection)。

同样在情节串连图板中,您需要创建具有唯一 ID 的单元原型。

有一些基本的单元格类型,比如(title,subtitle)——如果不需要特殊的配置,也可以使用它们。

因此,对于 picker,是的,您需要创建自己的定制单元格。创建必要的自定义 UITableViewCell类持有日期选择器,并确保使用委托将所需的结果返回到您的 ViewController

Let me start with answering your questions first.

我必须为每个单元格编写自己的类吗?是的,我想是的。至少我会这么做。

我可以使用一个 tableviewController 吗? = > 是的,你可以。但是,你也可以在你的视图控制器中有一个表格视图。

如何在不同的单元格中填充数据?根据不同的条件,可以在不同的单元格中填充数据。例如,假设您希望前两行与第一类单元格类似。因此,您只需创建/重用第一类单元格并设置它的数据。我想,当我给你们看屏幕截图时,会更清楚一些。

让我给你一个在 ViewController 中使用 TableView 的例子。一旦你理解了主要的概念,然后你可以尝试和修改任何你想要的。

步骤1: 创建3个自定义 TableViewCell。我将它命名为 FirstCustomTableViewCell,Second CustomTableViewCell,ThirdCustomTableViewCell。您应该使用更有意义的名称。

enter image description here

Step 2: Go the Main.storyboard and drag and drop a TableView inside your View Controller. Now, select the table view and go to the identity inspector. Set the "Prototype Cells" to 3. Here, you just told your TableView that you may have 3 different kinds of cells.

enter image description here

第三步: 现在,在 TableView 和标识检查器中选择第一个单元格,将“ FirstCustomTableViewCell”放在 Custom class 字段中,然后在属性检查器中将标识符设置为“ firstCustomCell”。

enter image description here

enter image description here

对所有其他类也这样做-将它们的自定义类分别设置为“ SecondCustomTableViewCell”和“ ThirdCustomTableViewCell”。还要连续地将标识符设置为 Second CustomCell 和 Third CustomCell。

步骤4: 编辑自定义单元格类并根据需要添加插座。我根据你的问题编辑的。

P.S: You need to put the outlets under the class definition.

因此,在 FirstCustomTableViewCell.swift 中,在

class FirstCustomTableViewCell: UITableViewCell {

你会把你的标签和图像视图插座。

 @IBOutlet weak var myImageView: UIImageView!
@IBOutlet weak var myLabel: UILabel!

并在 Second CustomTableViewCell.swift 中添加两个标签,如-

import UIKit


class SecondCustomTableViewCell: UITableViewCell {


@IBOutlet weak var myLabel_1: UILabel!
@IBOutlet weak var myLabel_2: UILabel!


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


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

and the ThirdCustomTableViewCell.swift should look like-

import UIKit


class ThirdCustomTableViewCell: UITableViewCell {


@IBOutlet weak var dayPicker: UIDatePicker!


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


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

步骤5: 在 ViewController 中,为 TableView 创建一个 Outlet 并设置来自故事板的连接。此外,还需要在类定义中添加 UITableViewDataSource 和 UITableViewDataSource 作为协议列表。 所以,您的类定义应该看起来像-

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

在此之后,将表视图的 UITableViewCommittee 和 UITableViewDatasource 附加到控制器。在这一点上,你的 viewController.swift 应该看起来像-

import UIKit


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {


@IBOutlet weak var tableView: UITableView!


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


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

PS: 如果您在 ViewController 中使用 TableViewController 而不是 TableView,那么您可以跳过这一步。

步骤6: 根据 Cell 类拖放单元格中的图像视图和标签。然后提供连接到他们的插座从故事板。

步骤7: 现在,在视图控制器中编写 UITableViewDatassource 所需的方法。

import UIKit


class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {


@IBOutlet weak var tableView: UITableView!


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


func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "firstCustomCell")
//set the data here
return cell
}
else if indexPath.row == 1 {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "secondCustomCell")
//set the data here
return cell
}
else {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "thirdCustomCell")
//set the data here
return cell
}
}


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

Swift 3.0 + 最小代码更新

基本概念: 使用动态单元格原型创建表视图。为每个单元格原型分配标识符并创建自定义表视图单元格类。在表视图的委托方法中初始化并显示自定义单元格。

1. Create cells on storyboard

将 tableView 拖动到视图控制器中,向其添加原型单元格,然后将 UI 元素拖放到表视图单元格中,如果需要,则正确添加约束。

enter image description here

2. 创建自定义 UITableViewCell

将下面的代码添加到项目中。

class FirstTableCell: UITableViewCell {
}


class SecondTableCell: UITableViewCell {
}


class ThirdTableCell: UITableViewCell {
}

3. Assign custom class and identifier to cell prototypes

对于故事板中的每个单元原型,分配从步骤2创建的自定义类,然后输入一个唯一标识符。

enter image description here

4. Connect UI elements to swift code

控件拖动表视图并连接到视图控制器类。控件拖动在步骤1中添加到单元格原型的 UI 元素,并连接到相应的表视图单元格类。

enter image description here

5. 向视图控制器添加代码并控制表视图

使视图控制器符合表视图委托

class YourViewController: UIViewController, UITableViewDataSource, UITableViewDelegate

viewDidLoad中,设置表视图的委托和数据源。

override func viewDidLoad() {
super.viewDidLoad()


self.tableView.dataSource = self
self.tableView.delegate = self


}

最后,根据最低要求添加两个委托方法来控制表视图。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "firstTableCell") as! FirstTableCell
// Set up cell.label
return cell
} else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "secondTableCell") as! SecondTableCell
// Set up cell.button
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "thirdTableCell") as! ThirdTableCell
// Set up cell.textField
return cell
}
}

6. Give it a try :)

enter image description here

以上的答案是最好的答案,但是得到这个问题的理由有很多。对于有这个问题的人,还有另一个可能的解决办法:

我的问题是,我正在转向 ViewController 类,而不是故事板视图。所以我对故事板单元的引用是没有意义的,因为故事板没有被使用。

我是这样做的:

let viewControllerB = SubViewController()
viewControllerB.passedData = diseases[indexPath.row].name
navigationController?.pushViewController(viewControllerB, animated: true)

And I needed to do something like this:

let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "SubViewStoryboardController") as! SubViewController
nextViewController.passedData = diseases[indexPath.row].name
self.present(nextViewController, animated:true, completion:nil)

希望这对谁有帮助。

我推荐使用这个简单易用的库,我为表和集合制作了视图。您可以根据需要添加任意类型的单元格,并在不使用样板代码的情况下实现更干净的 ViewController。

Https://github.com/deniskakacka/dkdatasources

对于第一张图片上的 UI,ViewController 中的所有代码如下:

lazy var dataSource = DKTableDataSource<CellType>(
models: [
DisclosureCellModel(title: "Disclosure 1", action: .action1),
TextFieldCellModel(title: "TextField 1", placeholder: "Placeholder 1"),
SwitchCellModel(title: "Switch 1", isOn: true),
BannerCellModel(imageName: "placeholder"),
SwitchCellModel(title: "Switch 2", isOn: false),
BannerCellModel(imageName: "placeholder"),
DisclosureCellModel(title: "Disclosure 2", action: .action2),
TextFieldCellModel(title: "TextField 2", placeholder: "Placeholder 2"),
BannerCellModel(imageName: "placeholder")
]
)


// in `viewDidLoad`
dataSource.registerCells(for: tableView)
tableView.dataSource = dataSource

如果使用自定义 XIBs 作为 TableView 单元格,请遵循下面的代码

 //Write in viewDidLoad()


let nib = UINib(nibName: "PrinterTVC", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "CELL1")
    

let nib1 = UINib(nibName: "SelectAndEditTVC", bundle: nil)
tableView.register(nib1, forCellReuseIdentifier: "CELL2")

Swift 5

  1. Create 3 Custom TableViewCells. I named it, FirstTableViewCell,SecondTableViewCell, Third TableViewCell

enter image description here

  1. 添加所有3个自定义单元格类,并根据您的需要添加插座。 我已经添加了以下代码。

    类 FirstTableViewCell: UITableViewCell {

    @IBOutlet weak var myImageView: UIImageView!
    @IBOutlet weak var myLabel: UILabel!
    
    
    static let cellIdentifier = "FirstTableViewCell"
    static let cellNib = UINib(nibName: "FirstTableViewCell", bundle: Bundle.main)
    override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
    }
    override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
    
    
    // Configure the view for the selected state
    }
    

    }

3: 在 ViewController 中,为 TableView 创建一个 Outlet。此外,还需要在类定义中添加 UITableViewDataSource 和 UITableViewDataSource。

@IBOutlet weak var tableView: UITableView!  {
didSet {
tableView.delegate = self
tableView.dataSource = self
tableView.register(FirstTableViewCell.cellNib, forCellReuseIdentifier: FirstTableViewCell.cellIdentifier)
tableView.register(SecondTableViewCell.cellNib, forCellReuseIdentifier: SecondTableViewCell.cellIdentifier)
tableView.register(ThirdTableViewCell.cellNib, forCellReuseIdentifier: ThirdTableViewCell.cellIdentifier)
}
}

现在,在视图控制器中编写 UITableViewDatassource 所需的方法。

    extension ViewController: UITableViewDelegate,UITableViewDataSource  {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: FirstTableViewCell.cellIdentifier, for: indexPath) as? FirstTableViewCell  else { return UITableViewCell() }
return cell
}else if indexPath.row == 1 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: SecondTableViewCell.cellIdentifier, for: indexPath) as? SecondTableViewCell  else { return UITableViewCell() }
return cell
}else  {
guard let cell = tableView.dequeueReusableCell(withIdentifier: ThirdTableViewCell.cellIdentifier, for: indexPath) as? ThirdTableViewCell  else { return UITableViewCell() }
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50 //According requirement
}
}

您的代码如下所示(查看控制器代码)

class ViewController: UIViewController {
            

@IBOutlet weak var tableView: UITableView!  {
didSet {
tableView.delegate = self
tableView.dataSource = self
tableView.register(FirstTableViewCell.cellNib, forCellReuseIdentifier: FirstTableViewCell.cellIdentifier)
tableView.register(SecondTableViewCell.cellNib, forCellReuseIdentifier: SecondTableViewCell.cellIdentifier)
tableView.register(ThirdTableViewCell.cellNib, forCellReuseIdentifier: ThirdTableViewCell.cellIdentifier)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
        

        

}
        

extension ViewController: UITableViewDelegate,UITableViewDataSource  {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: FirstTableViewCell.cellIdentifier, for: indexPath) as? FirstTableViewCell  else { return UITableViewCell() }
return cell
}else if indexPath.row == 1 {
guard let cell = tableView.dequeueReusableCell(withIdentifier: SecondTableViewCell.cellIdentifier, for: indexPath) as? SecondTableViewCell  else { return UITableViewCell() }
return cell
}else  {
guard let cell = tableView.dequeueReusableCell(withIdentifier: ThirdTableViewCell.cellIdentifier, for: indexPath) as? ThirdTableViewCell  else { return UITableViewCell() }
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50 //According requirement
}
}