When I create a tableview, I cannot click on any of the items I put on the tableview. I was wondering how can I create a tableview that has every item clickable and when the user clicks on an item( say a city name, for example) it redirects the user to a different viewcontroller. ( for example if there are 22 clickable items in the tableview, there will be a total of 22 new different viewcontrollers )
Thank you very much in advance!
There are three major functions that a UITableViewDataSource must contain for the table view to work properly with user interaction (Pressing each row, for example). These functions are:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
The function you are looking to use is the third one. It is called when a user selects a certain row by tapping it on screen. You can find out the row index with 'indexPath'.
If you would like to go to 22 different view controllers, you need to create a manual segue between each one and label them accordingly. Then, you would want to call each individual segue depending on which row was selected inside of that third function! You can call a segue with an identifier with the performSegue() function.
Note that the class that contains these functions must be of type UITableViewDataSource, and you should tell the table view that it is the data source in the ViewDidLoad() function like so:
tableView.dataSource = self
Here is what a simple code can look like:
import UIKit
class viewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var identifiers = [String]()
override func viewDidLoad() {
// fill your identifiers here
tableView.delegate = self
tableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return 22
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "yourCellIdentifier") as! yourCell
// fill your cell's data in here
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
// here you can use someThing like an array of your segue identifiers
self.performSegue(withIdentifier: identifiers[indexPath.row], sender: self)
//Or you can just implement a switch with every case doing what you want that cell to do which i don't recommend if you have 22 rows
}
}
Related
I am trying to learn tableView and custom cell. I was able to find some tutorials.
However, I need to be able to have informations to go from a cell to another, when the users are editing informations.
I also have a problem implementing the code like an Alert view to work on a cell, even know it's working on a view controller.
Can someone guide me toward a tutorial, as I have difficulty to found one.
As I said in my comment, you're asking too many questions in one, anyway this is a small TableView tutorial:
First thing first, you need to create your tableview:
var tableView: UITableView!
then you'll add it to your view:
//Put these in your view did load
//Change tose vaues as you please
tableView = UITableView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: 400), style: .plain)
view.addSubview(tableView)
So you'll need to register the cells:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell") //Choose the identifier you want but always use the same within a single Table view
You'll have to set the delegate and the data source:
//put these in your view did load
tableView.delegate = self
tableView = self
And your class will need to conform to these protocolls, so, you'll add the UITableViewDelegate and the UITableViewDataSource to it:
class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{}
So you'll have to set the protocol stubs as well:
//Here you'll decide the number of cells your tableView will have
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {}
//Here you'll decide the desired output of your cell (text, color ecc...)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//You have to create the cell first, it can be done as follows:
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) //Notice how I'm using the same identifier
return cell
}
There are plenty of other protocol stubs like:
//Use this to determine the behaviour of the cell when you tap it
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
//Use this to set the cell's height
private func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{}
You can find more in the apple documentation.
I am new to swift and I have this app in mind that basically needs to update all the cells based on the data received from one of the cells.
I am using dynamic cells and each one has a textfield inside.
TableViewController.swift:
import UIKit
class MyCells: UITableViewCell{
#IBOutlet weak var value_textfield: UITextField!
}
class TableViewController: UITableViewController {
var units_length: [String] = ["Centimeter", "Meter", "Foot"]
override func viewDidLoad() {
super.viewDidLoad()
units_length = units_length.sorted()
self.tableView.keyboardDismissMode = .onDrag
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return units_length.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = units_length[indexPath.row]
cell.textLabel?.textColor = UIColor.white
cell.textLabel?.font = UIFont(name:"DINAlternate-Bold", size:30)
return cell
}
override func viewWillAppear(_ animated: Bool){
tableView.rowHeight = 100
}
}
Which function should I use to access all the cells with different identifiers and simultaneously update all the textfield inside each cell?
I do have access to the textfield by having another class called MyCells, how should I implement it?
(I will not include the base ViewController class here as there's nothing inside)
Thanks!
Normally you use the function you already showed: cellForRowAt. You update your model data, tell the table to reloadData, cellForRowAt is called for all visible cells, and their values become the new values.
However if you are updating after every character, I would set up a notification broadcast situation and update all visible text fields and the model together without a reload. Just make sure the model and the table stay in sync in case the user scrolls and cellForRow is called.
I'm making a revision app for high school students. In this view, the user should be able to select the units that they want to study for a certain subject, and the index path of the selected units will be stored in an int array and passed on to the next view for displaying images. Unfortunately, the didSelectRowAt method is not responding for some reason.
The delegate and data source are set correctly, I know that it is not getting called as I wrote a print statement in the function, and nothing was printed in the console when I click on any one the table cells.
var units = [String]()
var selectedRows = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return units.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "unitCell", for: indexPath) as! UnitCell
cell.textLabel?.text = units[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedRows.append(indexPath.row)
print(selectedRows)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! ImageView
destination.folderNames = selectedRows
}
I expect an int array of row indexes of selected cells. But right now it is just empty.
If the code your showing in your question is accurate, the signature of the didSelectRowAt method is incorrect. It should be:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Note the leading "_" for the first parameter. If your class is a UITableViewController, you'll also need to add an override keyword.
If your code is already using this signature, please update your question to reflect that.
Also, this leading code cannot be correct. Please update it to what you're actually using,
var units = String var selectedRows = Int
You should use delegate method
optional func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath)
Instead of your existing one
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath)
Try and share your results.
First thing is that your didSectRow is depricated so please use
below one
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Secondly You have to set your TableView Delegate to Self like below
tableView.delegate = self
How do I programmatically add cells to a UITableview and fill the cells with data from myArray[cellNumber].
The data in the array is of type String. The tableview is just an UITableView connected with an outlet.
All the examples I've found is either +30 lines or doesn't work...
I'm using swift 4 and UIKit.
In Xcode, use "File > New > File > Cocoa Touch Class".
Use UITableViewController as a base class
You will find a big template, just implement:
numberOfSections(in tableView: UITableView) -> Int, make it return 1. You just need one section for now.
tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int, make it return the size of your array
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell. Uncomment it, implement it.
NOTE: To implement tableView(_:cellForRowAt:), you must in your storyboard register a cell, and use its name in this function. Or programmatically register a cell using register(_:forCellReuseIdentifier:) .
Here is a more comprehensive guide iOS Getting Started Guide UITableView
Implementation example:
override func numberOfSections(in tableView: UITableView) -> Int {
return 1 // Only one section
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// "cell" is registered in the Storyboard
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
// The registered cell, has a view with tag 1 that is UILabel as an example
// IndexPath is a data structure that has "section" and "row"
// It located the cell in your tableview/collectionview
(cell.viewWithTag(1) as? UILabel)?.text = myArray[indexPath.row]
return cell
}
1.Your ViewController must conform to the UITableViewDelegate, UITableViewDataSource.
That means your class file would look like this
class MyCustomViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
2.You must assign the dataSource and delegate properties of your UITableView object to your viewController either from the Storyboard by dragging or in the code in viewDidLoad for example by typing:
myTableView.delegate = self
myTableView.dataSource = self
3.Your class must override the UITableView required delegates/datasource methods numberOfRowsInSection and cellForRowAt:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = myArray[indexPath.row]
return cell
}
Note that to use dequeReusableCell you must set a Reuse Identifier for the cell in the storyboard file.
Currently I have a tableview that loads cells when I scroll down (scrollview). Is it possible to load and populate all cells on viewDidLoad. I would like to assign data to a cell before it can be viewed. I have tried using self.tableView.reloadData() but not successful.
If you don't want to use UITableView's cell reusing concept, then create all the UITableViewCells beforehand in viewDidLoad and store them in an array.
Example:
class ViewController: UIViewController, UITableViewDataSource
{
var arr = [UITableViewCell]()
override func viewDidLoad()
{
super.viewDidLoad()
//Create your custom cells here and add them to array
let cell1 = UITableViewCell()
let cell2 = UITableViewCell()
arr.append(cell1)
arr.append(cell2)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return arr.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
return arr[indexPath.row]
}
}