I have been searching for an answer on how to do this, but nothing seems straight forward, or the user wants to do something different(like selecting multiple cells).
Background:
I am making an app about retrieving quotes everyday for different professions such as Reading, gardening, sports. I have a UITabBarController with 3 tabs.
First tab = Quote ; Second tab = Categories ; Third tab = Settings *
The Settings tab is a UITableView with 3 sections, and 2 cells in each section.
Problem: I want to make each cell go to a different destination. The first cell in the first section will just be a view controller with a slider(color slider to change text color)(will get to that later). How would I be able to accomplish this?
import UIKit
class settingsTab: UIViewController, UITableViewDelegate {
struct Objects {
var sectionName : String!
var sectionObjects : [String]!
}
var objectsArray = [Objects]()
override func viewDidLoad() {
super.viewDidLoad()
objectsArray = [Objects(sectionName: "Options", sectionObjects: ["Change color of text" , "Notifications"]),Objects(sectionName: "Extras", sectionObjects: ["Remove ads" , "Restore purchases"]),Objects(sectionName: "Support", sectionObjects: ["Rate this app" , "Email developer"]), Objects(sectionName: "Jordan Norris - Quote Daily 2016", sectionObjects: [])]
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as UITableViewCell!
cell.textLabel?.text = objectsArray[indexPath.section].sectionObjects[indexPath.row]
cell.backgroundColor = UIColor.cyanColor()
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objectsArray[section].sectionObjects.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return objectsArray.count
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String?{
return objectsArray[section].sectionName
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
This is settingsTab.swift, where the TableViewController is established. If you need any more information, just comment what you would like to be added and I'll edit this post immediately. Thank you in advance!
You can access each section and each row through your last function didSelectRowAtIndexPath using indexPath.section and indexPath.row. For example if you want to access the second section and the first row, you can do
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Section \(indexPath.section), Row : \(indexPath.row)")
if indexPath.section == 1 && indexPath.row == 0{
//Code to implement View Controller to remove adds
print("Remove Adds")
}
}
Try selecting each row to show which section it prints and which row.
Will the number of sections and items in the section change? If not, creating static cells and hooking up a segue to each cell to a different destination can be done with no code (all in Interface Builder).
Related
I have a small tableview of 7 rows. I would like to enable different actions for a press of each row.
For example, the row at index 0 would display another VC (without passing data). The row at index 0 would open a web URL, the next might be a share function, etc.
My biggest problem is the first case of send the user to another VC. Mostly because I don't know if I should enable a segue. And for all cases, I need to be able to specify a function for each row separately, therefore I would need to specify the proper index (0,1,2,etc).
How can I do this is Swift?
Here is a skeleton of code you need:
class ViewController: UITableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 2 }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = String(describing: indexPath)
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
print("Do action for row 0")
} else if indexPath.row == 1 {
print("Do action for row 1")
}
}
}
I currently have UITableView that has one UITableViewCell within it. Within my code I created a button over this cell. When that button is pressed, the cells within it expand.
How would I go about making something expand when one of those cells are selected? Would I need to put a UITableView within the cell?
This is what I would do if I needed to bang something out in a hurry. Let each vegetable occupy its own table section, then expand or contract the section when the user toggles:
// We need some kind of data model.
class Vegetable {
init(name: String, facts: [String]) {
self.name = name
self.facts = facts
}
let name: String
let facts: [String]
var isShown: Bool = false // This flag gets toggled, which is why I've defined it as a class.
}
// And a table view controller configured for dynamic (not static!) cells. Create this in a storyboard, and change the UITableViewControllers class to VeggieTable.
class VeggieTable: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
veggieData = [Vegetable(name: "Tomato", facts: ["Number: 15", "Red Colored"]),
Vegetable(name: "Lettuce", facts: ["Good with peanut butter", "Green", "Crunchy snack"])] // etc.
}
var veggieData: [Vegetable]!
override func numberOfSections(in tableView: UITableView) -> Int {
return veggieData.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let veg = veggieData[section]
return veg.isShown ? veg.facts.count + 1 : 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let veg = veggieData[indexPath.section]
switch indexPath.row {
case 0:
cell.textLabel?.text = veg.name
default:
cell.textLabel?.text = veg.facts[indexPath.row - 1]
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let veg = veggieData[indexPath.section]
// Toggle the is shown flag:
veg.isShown = !veg.isShown
tableView.deselectRow(at: indexPath, animated: true)
// TODO: replace reloadData() with sophisticated animation.
// tableView.beginUpdates()
// tableView.insertRows() / deleteRows() etc etc.
// tableView.endUpdates()
tableView.reloadData()
}
}
Eventually you'd add table animations to make the rows appearing look smooth etc.
Hope that helps.
I am currently using a tableview to display a individual "Posts." In each tableview cell is a unique Post. I would like to add a collection of "comments" into each cell. The only way I can think about collecting comments is to add another TableView inside the Post's cell. What is some preferred methods to accomplishing this? It seems pretty complicated to use a TableView inside another TableViews Cell.
I don't think it's a good idea.
Create N sections in your table view, one section for every post.
For every section
the cell at row 0 will be populated with the post data
every cell in the following rows will be populated with the comments data.
Example
struct PostModel {
let title: String
let comments: [String]
}
class Posts: UITableViewController {
private var posts: [PostModel] = ... // TODO
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return posts.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts[section].comments.count + 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = posts[indexPath.section]
let cell = tableView.dequeueReusableCellWithIdentifier("StandardCell") ?? UITableViewCell(style: .Default, reuseIdentifier: "StandardCell")
if indexPath.row == 0 {
cell.textLabel?.text = post.title
return cell
} else {
let comment = post.comments[indexPath.row-1]
cell.textLabel?.text = comment
return cell
}
}
}
I have a problem with if statement and segue
can I make a connection between them !
I have an array of these states ["Florida","NY"]()
my idea, for example, if I clicked "Florida"<(this is "string") on table view
I want the segue moves me from this table view to another table view
and if I clicked "NewYork" on tableView I want the segue moves me from this table view to another that has information about NY
thanks
You could do something like this:
class SelectCityViewController : UITableViewController {
// store a reference to use in transition
var selectedCity : String?
let cities : [String] = ["New York", "San Francisco", "Los Angeles"]
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = //TODO: your implementation here
cell.textLabel?.text = cities[indexPath.row]
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedCity = cities[indexPath.row]
performSegueWithIdentifier("YOUR_SEGUE_IDENTIFIER", nil)
}
override func tableView(tableView: UITableView, numberOfItemsInSection section: Int) -> Int {
return self.cities.count
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let vc = segue.destinationViewController as? CityDetailViewController {
vc.selectedCity = self.selectedCity!
}
}
}
Then your second view controller would have a variable with your selected city stored in it so you could setup your content accordingly
class SelectedCityDetailViewController : UITableViewController {
// Set during the segue
var selectedCity : String!
// The rest of your methods
}
you can do something like this in didSelectRowAtIndexPath.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
if let text = currentCell.textLabel?.text {
if text == "Florida"{
// segue tableview controller
} else if text == "NY" {
//another segue
}
}
}
Take a viewController and add a tableView. Add two another view controllers, one for the NY info and the other containing one more uiTableView. Create two segues from main controller to the other two. Name the segues so that you can refer to them in the code. In didSelectRowAtIndexPath add the following Code:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
if indexPath.row == 0{
self.performSegueWithIdentifier("florida", sender: nil)
}else if indexPath.row == 1{
self.performSegueWithIdentifier("ny", sender: nil)
}
}
Please check this Link. I have created a demo project for you. I think you are a starter to the iOS development. Carry On!! :)
I understand that I need to implement required methods in the controller and establish a relationship between view and controller.. but where do the identifier "tableView" in
func tableView(mintabell: UITableView, numberOfRowsInSection section: Int) -> Int
{
return items.count
}
come from and what if I want several tableviews on same view? How to declare them separately?
These are the protocols that you need to declare for a TableView
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return createCellAndReturnItHere
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCellsInSection
}
In terms of having more than one tableview in one ViewController.. If you have an outlet for each tableview then you can check which one you need inside the protocol functions:
#IBOutlet weak var tableViewOne: UITableView!
#IBOutlet weak var tableViewTwo: UITableView!
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.tableViewOne {
return createCellForTableViewOneAndReturnItHere
} else {
return createCellForTableViewOneAndReturnItHere
}
}
Think of it like a box. Every tableView that is subscribed to the protocol grabs in that box leaves its fingerprint and takes what it gets. So if you have multiple tableViews in one controller you can distinguish them by checking for equality.
Example:
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let firstTableView = UITableView()
let secondTableView = UITableView()
viewDidLoad() {
firstTableView.delegate = self
secondTableView.delegate = self
firstTableView.dataSource = self
secondTableView.dataSource = self
}
// ... some othe methods...
func tableView(mintabell: UITableView, numberOfRowsInSection section: Int) -> Int
{
if tableView == firstTableView {
return 10
}
if tableView == secondTableView {
return 20
}
return 0
}
}
Delegates are implemented by the developer and called by iOS not the developer. The tableView is passed by iOS and points to the particular tableview.
If you have several tableviews with the same delegate you can compare the passed tableview parameter to the tableviews you have implemented to determine which one.
Alternatively, create a tableView delegate and datasource per tableView. This will eliminate testing which tableView removing a lot of conditional logic from the code.
First of all, you don't necessarily always have to implement a protocol for every view. Only when you have a view which has delegate that needs implementing, you will have to conform that protocol responsible for that delegate implementation.
So for tableView, first you drag a UITableView in your Controller from the Object Library and then a UITableViewCell under the Table View.
Now go to the ViewController.swift file and add
#IBOutlet var myFirstTableView: UITableView!
right after the line.
class ViewController: UIViewController
P.S: If you have more than one table then you could just declare the extra table's here., like-
#IBOutlet var mySecondTableView: UITableView!
Now, let's assume, you have one table. Now, you need to add the list of protocols. So, just add UITableViewDelegate, UITableViewDataSource with
class ViewController: UIViewController
appended by comma.
Adding this should give you an error but that's okay. This is because you have not added the required method listed under that UITableViewDatasource protocol.
So, just add those required methods and implement it accordingly.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as! UITableViewCell
cell.textLabel?.text = "test"
return cell
}
Here, I said, I will have 3 cells whose identifier is "myCell" and the cell's textLabel will have a text, "test".
Now, we forgot a very important step and that is to assign the cell identifier to our TableView Cell. So, go to the storyboard and select the TableView Cell and insert "myCell" as an identifier for your cell.
If you had more than one table, then you would check for which TableView, you are loading your data. So, you could assign a unique tag to each table explicitly(you can do that either from storyboard or from code), and based on that tag, you would implement your methods. Let's say you have 3 tables and the assigned tag is 1,2 and 3. So, you could do something like,
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView.tag == 1{
return 3
}
else if tableView.tag == 2{
return 4
}
else{
return 1
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
if tableView.tag == 1{
cell.textLabel?.text = "test1"
}
else if tableView.tag == 2{
cell.textLabel?.text = "test2"
}
else{
cell.textLabel?.text = "test"
}
return cell
}