I want to present a different view when selecting each Cell in a Table View.
I figured out that I have to use this function:
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
}
What should I add inside the function to make this work?
First of all, you need didSelectRowAtIndexPath and inside the function you could use indexPath.row to know witch cell was tapped and then you need to create and push the view you want
let viewControllerObj = self.storyboard?.instantiateViewControllerWithIdentifier("ViewControllerIdentifier") as? ViewController
self.navigationController?.pushViewController(viewControllerObj!, animated: true)
also, make sure your navigationController is not nil
...hope it helps
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
if indexPath.row == 0
{
let objOne = self.storyboard?.instantiateViewControllerWithIdentifier("ID_OneScene") as? OneScene
self.navigationController?.pushViewController(objOne!, animated: true)
}
else if indexPath.row == 1
{
let objTwo = self.storyboard?.instantiateViewControllerWithIdentifier("ID_TwoScene") as? TwoScene
self.navigationController?.pushViewController(objTwo!, animated: true)
}
else
{
let objOther = self.storyboard?.instantiateViewControllerWithIdentifier("ID_OtherScene") as? OtherScene
self.navigationController?.pushViewController(objOther!, animated: true)
}
}
Related
I have created a table view and add a custom table view cell . Inside the custom table view cell, i have added 4 labels and passed an array on each on of them . i have also enabled multiple row selection . i want to pass the selected rows to the next screen and display it there .
When you select row, every time UITableView didSelect call so you can make array for store value of selectedRow, If already in array than remove row.
selectedRow array you can pass in next screen use it.
For delete button i use mk_addTapHandler Button Extention you can see here
In my project same issue, but as per my design i put one button on cell for delete, i solved so You can use below code :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellDemo", for: indexPath)
cell.textLabel?.text = "\(indexPath.row)"
cell.btnDelete.mk_addTapHandler { (btn)
for (i,objValue) in selectedRow.enumerated() {
if indexPath.row == objValue {
self.selectedRow.remove(at: i)
for (i,objValue) in selectedRow.enumerated() {
if indexPath.row < objValue {
selectedRow[i] = objValue - 1
}else {
selectedRow[i] = objValue + 1
}
}
}
}
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedRow.append(indexPath.row)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
for (index, element) in selectedRow.enumerated() {
if indexPath.row == element {
selectedRow.remove(at: index)
}
}
}
#IBAction func doneClick(_ sender: Any) {
if let VC = self.storyboard?.instantiateViewController(withIdentifier: "nextScreen") as! nextScreen
VC.tableViewSelectedRow = selectedRow
self.navigationController?.pushViewController(VC, animated: true)
}
}
If you have already enabled multi-row selection in the tableView it's relatively straightforward. In your button action method get the indexPaths of your selected rows and then use them to extract the data from your datasource and inject them into the next viewController. The below gives you core functionality but as you have not shared your code for datasource or table design, or indicated whether you are using IB or code for your app, you will have to make it fit your environment.
Assumptions:
you have a simple tableView with only one section and all rows are possible data for the next VC
you are doing your UI in code, and want to push rather than present the next VC
your data for your view is in an array called mainData
your next view controller is a class called NextViewController
#objc doneButtonTapped(_ sender: UIButton) {
let indexPaths = tableView.indexPathsForSelectedRows
let selectedData = indexPaths.map{mainData[indexPath.row]}
let nextVC = NextViewController()
nextVC.data = selectedData
navigationController?.pushViewController(nextVC, animated: true)
}
I am new to Swift (I use 2.0) and haven't any programmed experience. So, I'm new ) trying to do something fairly simple. Link a UITableViewCell click to call a different ViewController. It's like user click on cell Cars and open new ViewController.
I have created ViewControllers (storyboard A,B,C,D,E).
How I can connect? If I correctly understood I should use didSelectRowAtIndexPath.
Code which I have done:
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let list = ["Cars", "Fruits", "Foods", "Toys"]
let listdesc = ["Toyota", "Apple", "Meat", "Fallout 4"]
let identities = ["A", "B", "C", "D"]
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier: String = "cell"
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: cellIdentifier)
cell.textLabel?.text = list[indexPath.row]
cell.detailTextLabel?.text = listdesc[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
You should have to do in this way in didSelectRowForIndexPath:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let StoryBoard = UIStoryboard(name: "Main", bundle: nil)
if(list[indexPath.row] == "Cars") {
var vcA = STORYBOARD.instantiateViewControllerWithIdentifier("A") as! A
self.navigationController?.pushViewController(vcA, animated: true)
} else if(list[indexPath.row] == "Fruits") {
var vcB = STORYBOARD.instantiateViewControllerWithIdentifier("B") as! B
self.navigationController?.pushViewController(vcB, animated: true)
}
}
and other condition you will manage as I show....
As answered by Gaurav, you can check in didSelectRowAtIndexPath that which indexPath is selected and then navigate to that respective controller.
But if you are using different storyboards then self.storyboard instead of STORYBOARD may come in handy.
Also change the objects of your viewController from var to let as you are not changing them so they should be constants.
And the last one "Always avoid force unwrapping", handle the error yourself instead.
Try this.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// If storyboard name is A.storyboard.
let storyboard = UIStoryboard(name: "A", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("nextViewControllerId") as! nextViewController // The `nextViewController` storyboardId is supposed as "nextViewControllerId"
self.presentViewController(vc, animated: true)
}
This will present nextViewController every time you click any cell. If you want specific cell to open different viewcontroller use you logic using conditions within this function.
1. Create a segue from TableViewController Scene to other
ViewControllerScene.
2. Give unique identifier to each scene.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//Based on your condition.
//Initiates the segue with the specified identifier from the current view controller's storyboard file.
performSegue(withIdentifier: "segueA", sender: self)
}
If you have three storyboard like Main, PreLogin and PostLogin. Then you declare first all storyboard like this:-
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let preLoginStoryboard = UIStoryboard(name: "PreLogin", bundle: nil)
let postLoginStoryboard = UIStoryboard(name: "PostLogin", bundle: nil)
You call different viewController from the didSelectRowAtIndexPath method like that:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch indexPath.row{
case 0:
let firstViewControllerScene = mainStoryboard.instantiateViewControllerWithIdentifier("firstViewControllerId") as! FirstViewController
self.presentViewController(firstViewControllerScene, animated: true)
case 1:
let secondViewControllerScene = preLoginStoryboard.instantiateViewControllerWithIdentifier("secondViewControllerId") as! SecondViewController
self.presentViewController(secondViewControllerScene, animated: true)
case 2:
let thirdViewControllerScene = postLoginStoryboard.instantiateViewControllerWithIdentifier("thirdViewControllerId") as! ThirdViewController
self.presentViewController(thirdViewControllerScene, animated: true)
default:
break
}
}
You have to prepare data something like this and
options = [
{
"category":"Cars"
"subcat":"Cars"
"viewType":"A"
},
{
"category":"Fruits"
"subcat":"Apple"
"viewType":"B"
},{
"category":"Foods"
"subcat":"Meat"
"viewType":"C"
}
]
It's not exactly copy paste answer for you, but you need to create a data like data.
You need to modify data all together so for particular index with in single dictionary object you will get all data at once. If as your array will not have proper data then you app may crash if index will will not proper.
Then for particular index you can get viewType. you can compare it with required type and get the viewcontroller reference and push it.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if(options[indexPath.row]["viewType"] == "A") {
// Get A controller reference and use it
}else if(options[indexPath.row]["viewType"] == "B") {
// Get A controller reference and use it
}else if(options[indexPath.row]["viewType"] == "C") {
// Get A controller reference and use it
}
}
I hope you will understand the structure. Please, let me know if you are not clear.
Updated:
To get reference from storyboard,
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "someViewController") as! UIViewController
self.present(controller, animated: true, completion: nil)
I'm working with swift 2.2 and xcode 7.3 . I am trying to load a table view from another tableview when a row gets clicked . In
didSelectRowAtIndexPath
of the first table View , I create an instance of the other table view class and call it using the pushViewController . But the table view doesn't get loaded and screen remains the same. My code is
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
NSLog("It did enter the didselectRowAtIndexPath")
if (indexPath.section == 0){
let enrolledView = DetailsViewController()
navigationController?.pushViewController(enrolledView, animated: true)
}
if (indexPath.section == 1){
let appcatalog = AppCatalogViewController()
navigationController?.pushViewController(appcatalog, animated: true)
}
if (indexPath.section == 2){
let support = supportViewController()
navigationController?.pushViewController(support, animated: true)
}
}
Note : "It did enter the didselectRowAtIndexPath" gets printed in the log . SO Kindly let me know if there is something that am not doing correctly .
Could you give us a bit more of your code?
For example how have you embedded your class in a navigation controller?
Because if nothing appears it is probably due to the fact that navigationController is nil
I think you have two mistakes in your code.
The first one:
You haven't embedded your controller into a UINavigation controller.
The second One:
You are not initiating your view controller before your could move onto it.First assign a storyboard identifier to each of your view controller. So change your code as:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
NSLog("It did enter the didselectRowAtIndexPath")
if (indexPath.section == 0){
let enrolledView = self.storyboard?.instantiateViewControllerWithIdentifier("identifier of your DetailsViewController")
navigationController?.pushViewController(enrolledView, animated: true)
}
if (indexPath.section == 1){
let appcatalog = self.storyboard?.instantiateViewControllerWithIdentifier("identifier of your AppCatalogViewController")
navigationController?.pushViewController(appcatalog, animated: true)
}
if (indexPath.section == 2){
let support = self.storyboard?.instantiateViewControllerWithIdentifier("identifier of your supportViewController")
navigationController?.pushViewController(support, animated: true)
}
}
This question already has an answer here:
Table view didSelectRowAtIndexPath, only works after selecting second click
(1 answer)
Closed 7 years ago.
So here's the thing:
I implemented a UITableViewController with a custom cell..
Then i replaced the automatic segue cell to viewcontroller (storyboard) with viewcontroller to viewcontroller.
Code from my UITableViewController:
// MARK: - Tableview managment
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var lobbycell = tableView.dequeueReusableCellWithIdentifier("lobbycell") as! LobbyTableViewCell
let row = indexPath.row
if let channel = lobbies[row].lobbyName {
lobbycell.lobbynameLabel.text = channel
}
if let usercount = lobbies[row].users?.count {
lobbycell.usercountLabel.text = "Anzahl Spieler: \(usercount)"
}
if let host = lobbies[row].host?.username {
lobbycell.hostnameLabel.text = "Host: \(host)"
}
return lobbycell
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lobbies.count
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let selectedLobby = lobbies[indexPath.row]
var loading = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
PFLobby.joinLobbyInBackgroundWithBlock(selectedLobby, user: PFUser.currentUser()!) { (success, error) -> Void in
loading.hide(true)
if success {
self.performSegueWithIdentifier("joinLobby", sender: self)
} else {
}
}
}
Now here's the problem:
If I click on a cell it's going to get gray (like selected) but won't call the didDeselectRowAtIndexPathfunc..
Only If I click on another cell it's going to call the didDeselectRowAtIndexPathwith the gray (like selected) cell's indexPath.
Are you confused with didSelectRowAtIndexPath and didDeselectRowAtIndexPath?
The latter will only be called if it's deselected, hence why it's called after you select another cell.
If you want to call the didDeselectRowAtIndexPath, then add the method deselectRowAtIndexPath in didSelectRowAtIndexPath and it will deselect right way.
This is expected behavior. tableView(_:didDeselectRowAtIndexPath:) will only be called after another cell is selected.
If you want, it is possible to intercept the selection event in tableView(:_willSelectRowAtIndexPath:):
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
if let selectedIndex = tableView.indexPathForSelectedRow() where selectedIndex == indexPath {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
return nil
}
return indexPath
}
The index path returned by this method will be selected. If you return nil, nothing will get selected.
I have a tableView(top) and a view controller(bottom) within container views in the same view. I need to send info and refresh the bottom view when selecting a table row. I'd like it to work like the apple stocks app. I originally had the bottom view on another page and used a segue and it worked great. But I'm not sure how to do it without a segue now.
Here is the code for selecting the row:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
let item = items[indexPath.row]
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
What I had before for the segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let controller = segue.destinationViewController as SNPDetailViewController
if let indexPath = tableView.indexPathForCell(sender as UITableViewCell) {
controller.itemToEdit = items[indexPath.row]
}
}
And what was working when I used the segue in the (now) bottom view:
override func viewDidLoad() {
super.viewDidLoad()
if let item = itemToEdit {
title = item.name
snpDetails.text = item.details
}
}
Any help is greatly appreciated!
In your table view controller, self.parentViewController will point to the container view controller. Then you can get a reference to the existing detail view controller via the childViewControllers property of the container:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
let item = items[indexPath.row]
if let vc = self.parentViewController {
let siblings = vc.childViewControllers
if siblings.count > 1 {
if let detailVC = siblings[1] as? SNPDetailViewController {
detailVC.itemToEdit = item
} else {
println("Odd, that detail view controller is not the right class")
abort()
}
} else {
println("Odd, there is no detail view controller")
abort()
}
} else {
println("Strange, I'm not embedded in a parent view controller")
abort()
}
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
This assumes your table view controller is at index 0 of childViewControllers, and the detail view controller is at index 1. Amend siblings[1] to siblings[0] if it's the other way around.
You may need to implement a setter method for itemToEdit in order to reload the labels etc when the value changes.
I guess your bottom view is SNPDetailViewController
As you can see in your previous code you had a variable called controller. That variable is missing in your actual code. Try to create it in your first snippet of code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
let item = items[indexPath.row]
}
let controller = SNPDetailViewController()
// then you can call the _itemToEdit_ method in your other view
if let indexPath = tableView.indexPathForCell(sender as UITableViewCell) {
controller.itemToEdit = items[indexPath.row]
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
I'm not completely sure if that works but the idea is that you need like an instance of your bottom view to access its methods. Let me know if that helps.