I am having an issue with designing a storyboard. I currently have an app in the app store that was designed with XIB files. I have a tableView placed on a UIViewController - not a tableViewController - that loads a unique viewController for each row that is selected.
I am trying to convert this concept to a storyboard. I've done the following
Place a UIViewController in the Storyboard.
Place a UITableView on the UIViewController so I can customize the table view.
I tried making connections to multiple ViewControllers from the UITableViewCell and I am not allowed.
I tried creating multiple segues from the UIViewController - which I can - but when I click on the cells the segues are not fired. I tried using didSelectRowAtIndexPath: and prepareForSegue:
Since this did not work I tried creating a project with a UITableViewController and then created multiple segues from the UITableViewController. I then named each segue and used the didSelectRowAtIndexPath: method to test the selected cell and called performSegueWithIdentifier: and this did not work. As I clicked on cells I would get random loading of the incorrect viewController. I've copied a bit of my code and few screen shots below.
I am wondering if I am blatantly missing something obvious or do I have to revert to a xib format for this type of project?
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath)
{
if indexPath.row == 0
{
println("Segue1")
self.performSegueWithIdentifier("Segue1", sender: self)
}
else if indexPath.row == 1
{
println("Segue2")
self.performSegueWithIdentifier("Segue2", sender: self)
}
else if indexPath.row == 2
{
println("Segue3")
self.performSegueWithIdentifier("Segue3", sender: self)
}
}
Take care,
Jon
The method
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) is called when an item is deselected.
To call a method when an item is selected, change the method name to override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
I used a combination of the comment by Allen. Initially I wasn't able to create the segues I needed. I created a navigation controller that uses my own view controller that holds a tableview. Then I created the associated cells for the prototype cells and switched them to a static cell. I only have a limited amount, 3 at the time. This allowed me to created the segues to the appropriate views in the storyboard. Then I changed the cells back to prototype cells and it maintained the connection to the segues. All that is left was creating the associated switch statement in the table view to go to the correct segue. Just make sure you name your segues with the identifiers listed in your code.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath:NSIndexPath) {
//Add cases here to move to different segues
switch indexPath.row{
case 0: self.performSegueWithIdentifier("courses", sender: self);
break;
case 1: self.performSegueWithIdentifier("finals", sender: self);
break;
case 2: self.performSegueWithIdentifier("academic", sender: self);
break;
default:
break
}
}
Swift 3 Code
Well, look at my piece of code I use to perform dynamic segue based on the type of the device type in the cell. :) Hope it helps.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let device = Cache.DEVICELIST[indexPath.row]
let deviceType = device.type
switch deviceType {
case "camera":
self.performSegue(withIdentifier: "DashCellToCamera", sender: self)
case "gateway" :
self.performSegue(withIdentifier: "DashCellToGateway", sender: self)
case "tracker" :
self.performSegue(withIdentifier: "DashCellToTracker", sender: self)
case "panicbutton" :
self.performSegue(withIdentifier: "DashCellToPanicButton", sender: self)
default:
break
//do nothing just ignore this
}
}
Related
I have an iPad TabBar navigation app and in OrderViewController I have a tableview on left side and outlets on the right side of the view as in a sort of split view controller. When you click a tableView's cell it shows details on the other half screen. As I'm introducing two different color schemes for A/B testing, I use a switch to perform the change in color. The color switching dough doesn't succeed with tableView's cells. Adding a reloadData() in viewWillAppeardidn't solve the problem.
Everything gets updated except for the cells, they maintain the colors of when they got created the first time.
I added prints throughout the phases and I detected that cell's awakeFromNimbgets called only the first time. How do I get it to be called on tableView.reloadData()? As always many thanks.
awakeFromNib():
override func awakeFromNib() {
super.awakeFromNib()
configureUi()
}
viewWillAppear():
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.configureFetchedResultsController()
orderTableView.delegate = self
orderTableView.dataSource = self
configureUI()
orderTableView.reloadData()
}
Use the tableView delegate willDisplayCell
https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614883-tableview
class MyCustomVC: UITableViewDelegate {
override func tableView(_ tableView: UITableView,
willDisplay cell: UITableViewCell,
forRowAt indexPath: IndexPath) {
guard var cell = tableView.dequeueReusableCell(withIdentifier: "yourReuseIdentifier", for: indexPath) as? YourCustomCell else {
return UITableViewCell()
}
cell.configureUi()
}
}
I am relatively new to Swift - developing an app for my hospital (I'm a resident physician) that's essentially a mobile reference tool that I'm building with a series of tableViews.
PROBLEM: I cant get my Segues to work from my Prototype cells to multiple VCs.
My initial VC is a tableVC, with prototype cells that I built into two sections using a nested array. Seen here
The destination VCs are also TableVCs, I want each tableCell of the initialVC to segue to a different destination TableVC.
I was able to set some Segues from my initialTVC to the destinationTVCs, I also have embedded a Navigation Controller -->
Here's what my storyboard setup looks like
What I'm trying to do for the Segues:
Set up the segue ID that I gave each segue in storyboard using the prepareForSegue function
Use didSelectRowAtIndexPath, with some If statements specifying which cell I want to do which segue, to execute the segue.
Keep that Storyboard Navigation controller in place - love the functionality and easy implementation it provides considering I'm going to add one more level of these segues as "submenus" before getting to my detailView pages.
Here's my Swift 3 code:
// MainTableViewController.swift
import UIKit
class MainTableViewController: UITableViewController {
var MainTitleArray = [["Children and Pregnant Women", "Mental Health and Addiction", "Hunger and Food Insecurity", "Legal Aid", "Housing, Heat, and Emergency Assistance", "New Immigrants, Refugees, and the Underserved", "The Uninsured and the Underinsured"], ["Primers and the Private Sector", "Federal Programs", "Social Securty"]]
var SubTitleArray = [["Resources for the most vulnerable in the family", "The programs to help those who need it", "When every night is a worry about food on the table", "How to defend yourself in a complicated system", "HEalth follows you into the home", "Your patient needs help - can they sign up worry-free?", "What to do when your options are limited"], ["What you need to know","Medicare Medicaid - What are they?","Disability and Insurance"]]
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 90
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return MainTitleArray.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return MainTitleArray[section].count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainCell", for: indexPath) as! MainTableViewCell
cell.MainTitleLabel.text = MainTitleArray[indexPath.section][indexPath.row]
cell.MainSubTitleLabel.text = SubTitleArray[indexPath.section][indexPath.row]
return cell}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (indexPath.section == 0) && (indexPath.row == 0) {
self.performSegue(withIdentifier: "CPWSegue", sender: indexPath);
}
else { self.performSegue(withIdentifier: "MHASegue", sender: indexPath)
}}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "CPWSegue" {
let destVC = segue.destination as! CPWTableViewController
destVC.VCName = "CPW"}
}
}
I build this successfully but the segues just arent working still. I almost would rather still have some error code to get something to work with! If anyone has any helpful suggestions/comments/links for further reading, would HUGELY appreciate it. Have read through TONS of other pages and documents to try and get this to work as simply as I want it to, but no dice so far. Thanks in advance for any help you can offer!
UPDATE on 4/20/17: I've edited the prepareForSegue function, even put in a "VCName" var in so I can call segue.destination (even though "VCName" is not used) - STILL not giving me a segue (no error msg, and its successfully building) and not sure what to try next. Any advice appreciated!
UPDATE on 4/26/17: I used some break points and found out that neither the prepare nor perform segue functions were firing. I rebuilt and made sure it was an override function of the superclass (no idea why it wouldnt let me do that before hand), and it worked! Special thanks to Sasaang for the help!
Your code looks good from what i can tell, and it should work with this minor change. Remember that sections and rows are indices starting at 0. You have the following:
if (indexPath.section == 1) && (indexPath.row == 1) {
self.performSegue(withIdentifier: "CPWSegue", sender: indexPath);
}
I suspect you are tapping on the first item in the first section and not seeing any transitions, but the code above actually refers to the second item in the second section. The "Federal Programs" cell. Change the code to the following to be able to tap the "Children and Pregnant Women" cell to segue to the next ViewController.
if (indexPath.section == 0) && (indexPath.row == 0) {
self.performSegue(withIdentifier: "CPWSegue", sender: indexPath);
}
Additioanlly i would suggest you save some code by adding all of your ViewController StoryBoard Id's into a similar array structure as your main title array, that way instead of many if-else statements in the didSelectRowAtIndexPath function, you can change it to simply:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegue(withIdentifier: identifierList[indexPath.section][indexPath.row], sender: indexPath);
}
UPDATE
Additional note on updated question. The prepareForSegue function is just there to stage the next scene before presenting it. Like for instance if there's a "name" field in the CPW viewController, you can set it in the function like so before presenting it:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "CPWSegue" {
let nextView = segue.destination as? CPWView
nextView.name = "SOME NAME"
}
}
You don't call performSegue() there again, its already happening.
I am a beginner coder in swift. I am trying to create a tabbed application. For one of my tabs, I am creating a table view which has multiple rows each which have a different task (A good way to think of this is the facebook app, where each option in the more screen will take you to a separate view)
Now, my table is populated with an array:
let array = ["one", "two", "three]
I want to ask, that everytime that I tap on one of these rows, I would like to go a new view controller. How is this possible?
What I tried was performSegue with an identifier which I give in the storyboard, but then there would be an x amount of segues connecting to the table view? So I don't think this is right? :/
I know the contents of the array prior to generating the table, so If I know the array value, and the row being tapped, how can I navigate to a new view controller?
Edit:
When performing the segue between the controllers, I am using:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: "showView", sender: self)
}
This of course will only connect to the segue showView however, how can i add multiple view controllers?
You need to simply compare which row is selected in tableView and then perform segue according to it.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let segueIdentifier: String
switch indexPath.row {
case 0: //For "one"
segueIdentifier = "showView1"
case 1: //For "two"
segueIdentifier = "showView2"
default: //For "three"
segueIdentifier = "showView3"
}
self.performSegue(withIdentifier: segueIdentifier, sender: self)
}
Add the following function to your controller.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
navigationController?.pushViewController(NewController(), animated: true)
}
Using Static Cells in a UITableViewController
Summary
An alternative is to use a UITableViewController with static cells. If you know already know the menu then you can just create static cells for each item.
In the storyboard you can connect a segue from each cell to their respective view controllers.
Example
i have a two view application. If i select a row a segue load the second view Controller. I want that when i return back to my first controller the row is is still selected. I have tried with this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.cellForRowAtIndexPath(indexPath)!
self.tableView.selectRowAtIndexPath(indexPath, animated: true, scrollPosition: UITableViewScrollPosition.None)
}
override func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
but when returning back the row not remain selected. What's is the problem??
P.S.: I want no multiple selection, only one row at time.
If you are using a UITableViewController subclass as your source view controller, what I presume because you are overriding the table view delegate methods, you can use the flag clearsSelectionOnViewWillAppear on your view controller to get this behavior.
override func viewDidLoad() {
self.clearsSelectionOnViewWillAppear = false
}
Or you can set this in your Storyboard as well, when selecting the attributes selector of your source table view controller, you have to untick the Clear on Appearance checkbox.
I'm very new to swift. I added disclosure indicators to my TableView. I want to make the different disclosure indicators lead to different view controllers. Can anyone help me with this?
Connect your ViewController with multiple ViewControllers in your storyboard giving each storyboard segue an identifier. Then call self.performSegueWithIdentifier when you have identified which cell the user has selected. For example:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
self.performSegueWithIdentifier("yourIdentifier", sender: self)
}
...
}