Swift Tableview for iOS

UITableView example for Swift

The example below is an adaptation and simplification of a longer post from We ❤ Swift. This is what it will look like:

Sample Image

Create a New Project

It can be just the usual Single View Application.

Add the Code

Replace the ViewController.swift code with the following:

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

// Data model: These strings will be the data for the table view cells
let animals: [String] = ["Horse", "Cow", "Camel", "Sheep", "Goat"]

// cell reuse id (cells that scroll out of view can be reused)
let cellReuseIdentifier = "cell"

// don't forget to hook this up from the storyboard
@IBOutlet var tableView: UITableView!

override func viewDidLoad() {
super.viewDidLoad()

// Register the table view cell class and its reuse id
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)

// (optional) include this line if you want to remove the extra empty cell divider lines
// self.tableView.tableFooterView = UIView()

// This view controller itself will provide the delegate methods and row data for the table view.
tableView.delegate = self
tableView.dataSource = self
}

// number of rows in table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.animals.count
}

// create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

// create a new cell if needed or reuse an old one
let cell:UITableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as UITableViewCell!

// set the text from the data model
cell.textLabel?.text = self.animals[indexPath.row]

return cell
}

// method to run when table view cell is tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("You tapped cell number \(indexPath.row).")
}
}

Read the in-code comments to see what is happening. The highlights are

  • The view controller adopts the UITableViewDelegate and UITableViewDataSource protocols.
  • The numberOfRowsInSection method determines how many rows there will be in the table view.
  • The cellForRowAtIndexPath method sets up each row.
  • The didSelectRowAtIndexPath method is called every time a row is tapped.

Add a Table View to the Storyboard

Drag a UITableView onto your View Controller. Use auto layout to pin the four sides.

Sample Image

Hook up the Outlets

Control drag from the Table View in IB to the tableView outlet in the code.

Finished

That's all. You should be able run your app now.

This answer was tested with Xcode 9 and Swift 4



Variations

Row Deletion

You only have to add a single method to the basic project above if you want to enable users to delete rows. See this basic example to learn how.

Sample Image

Row Spacing

If you would like to have spacing between your rows, see this supplemental example.

Sample Image

Custom cells

The default layout for the table view cells may not be what you need. Check out this example to help get you started making your own custom cells.

Sample Image

Dynamic Cell Height

Sometimes you don't want every cell to be the same height. Starting with iOS 8 it is easy to automatically set the height depending on the cell content. See this example for everything you need to get you started.

Sample Image

Further Reading

  • iOS & Swift Tutorial: UITableViewController
  • iOS Table View Tutorial Using Swift

Problem with adding tableview into tableview cell swift

I suggest you use only one tableview, here some example

struct Answer {
let answerText: String
}

struct Question {
let questionText: String
let answers: [Answer]
}

class ViewController: UIViewController {

@IBOutlet weak var tableView: UITableView!
var questions: [Question] = []

override func viewDidLoad() {
super.viewDidLoad()

for i in 1...10 {
let question = Question(questionText: "Question \(i)", answers: [
Answer(answerText: "Answer 1 Question \(i)"),
Answer(answerText: "Answer 2 Question \(i)"),
Answer(answerText: "Answer 3 Question \(i)"),
Answer(answerText: "Answer 4 Question \(i)")
])
questions.append(question)
}
tableView.dataSource = self
tableView.delegate = self
tableView.sectionHeaderHeight = UITableView.automaticDimension;
tableView.estimatedSectionHeaderHeight = 44
}


}

extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return questions.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questions[section].answers.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AnswerCell", for: indexPath) as! AnswerCell

cell.answerLabel.text = questions[indexPath.section].answers[indexPath.row].answerText
return cell
}

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionCell") as! QuestionCell

cell.questionLabel.text = questions[section].questionText
return cell
}
}

Sample Image

Search through tableview data and handle row selection in Swift

As already mentioned in the comments it's highly recommended that the data source and the filtered array are of the same type.

And declare both as non-optional empty arrays and give them more meaningful names

var employees = [Employee]()
var filteredEmployees = [Employee]()

Then the data source methods become quite simple

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searching ? filteredEmployees.count : employees.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell
let employee = searching : filteredEmployees[indexPath.row] : employees[indexPath.row]
cell.lblTitle.text = employee.emp_name
return cell
}

And in textDidChange you have to consider that the user can delete all characters

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.isEmpty {
searching = false
filteredEmployees.removeAll()
} else {
searching = true
filteredEmployees = employees.filter{$0.emp_name.range(of: searchText, options: .caseInsensitive) != nil}
}
tableView.reloadData()
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
}

How to fill UITableView with a data from Dictionary. Swift

I used a struct Rate to Reproduce your current Output

struct Rate {
var ask : Float?
var bid : Float?

static var shared = Rate()

mutating func initWithDictValues(_ currentRate : Rate) {
self.ask = currentRate.ask
self.bid = currentRate.bid
}
}

Currencies Array

/// Array Declaration
var currencies = [String:Any]()

/// Add Values
currencies = ["EUR":Rate(ask: 30.8500, bid: 30.8500),"USD":Rate(ask: 26.3000, bid: 26.3000),"RUB":Rate(ask: 0.4150, bid: 0.4150)]

Get All Keys in Separate Array so we can Dequeue cell Easily

var keysArray = Array(currencies.keys)

TableView Function

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CurrencyCell", for: indexPath) as! CurrencyCell

/// Get CurrentKey
let currentKey = keysArray[indexPath.row]
let currentIndexKey : Rate = currencies[currentKey] as! Rate

/// Assign Values
cell.currencyLabel.text = currentKey
cell.askLabel.text = currentIndexKey.ask ?? 0
cell.bidLabel.text = currentIndexKey.bid ?? 0

return cell
}

Playground Output

Sample Image

Hope this helps

Swift TableView Cell Unable to Display the data from API

You are registering a generic cell:

self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DisplayView1")

You need to register your custom cell:

self.tableView.register(DisplayView.self, forCellReuseIdentifier: DisplayView.identifier)

Swift UITableView messing up after reloadData()

This is because of the reuse of cells.

Set the default color in else condition.

} else {
cell.cost.textColor = UIColor.gray
cell.cost.text = "\(items[indexPath.row].XP) XP"
}

Another way, you can set the default style property inside the prepareForReuse method of UITableViewCell

class TableViewCell: UITableViewCell {
override func prepareForReuse() {
super.prepareForReuse()
// Set default cell style
}
}

(Swift) How to hide some sections in tableView when toggle switch is on?

Approach:

In your Model, you can create a isHidden property that will keep a track of whether the section should be hidden or not, i.e.

class Model {
var sectionName: String
var isHidden = false

init(sectionName: String) {
self.sectionName = sectionName
}
}

Now, modify the UITableViewDataSource methods to,

class VC: UIViewController, UITableViewDataSource, UITableViewDelegate {
let arr = [Model(sectionName: "Section 1"), Model(sectionName: "Section 2"), Model(sectionName: "Section 3"), Model(sectionName: "Section 4"), Model(sectionName: "Section 5")]
lazy var dataSource = self.arr

func numberOfSections(in tableView: UITableView) -> Int {
return dataSource.count
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.cellSwitch.setOn(false, animated: false)
cell.labelCell.text = dataSource[indexPath.section].sectionName
cell.callback = {[weak self] in
guard let `self` = self else {
return
}
self.arr[indexPath.section].isHidden = !(self.arr[indexPath.section].isHidden)
self.dataSource = self.arr.filter({ !$0.isHidden })
tableView.reloadData()
}
return cell
}
}

And you can simply call the closure callback?() in toggleSwitch(_:) and the hiding/unhiding will be handled automatically.

class TableViewCell: UITableViewCell {
@IBOutlet weak var labelCell: UILabel!
@IBOutlet weak var cellSwitch: UISwitch!

var callback:(()->())?
@IBAction func toggleSwitch(_ sender: Any) {
callback?()
}
}

IOS UITableView display first 5 rows of an array

You can't share a single visual effect view which you move between cells. (A view can only exist once in thew view hierarchy. If you add it as a subview in 2 places, it gets removed from the first place).

Your code should also use if indexPath.row >= 5, not if indexPath.row == 5

I would suggest creating a custom subclass of UICollectionViewCell that has a public blurView IBOutlet. Install a blur view in the cell in your XIB/storyboard. In your tableView(_:cellForRowAt:) method, hide the blur view if the row is < 5, else un-hide it.



Related Topics



Leave a reply



Submit