In ViewController A I have a TableView with two trailingSwipeActions and one leadingSwipeAction. If you tap on the cell there is a segue to ViewController B. The trailingSwipeActions call ActionSheets, handled inside ViewController A. The segue is executed from within the 'prepare for segue' function. That all works super.
Now I want to add another segue for if you perform the leadingSwipeAction. That segue has to lead to ViewController C. I can't add another segue in the Storyboard, from the customcell to ViewController C... then when I click on the cell... just one segue gets called (and not the other). So... what to do.
Here is the relevant part of my code:
override func tableView(_ tableView: UITableView,
leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration?
{
let weightAction = UIContextualAction(style: .normal, title: "Gewicht", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
success(true)
})
weightAction.image = UIImage(named: "Scale")
weightAction.backgroundColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1)
return UISwipeActionsConfiguration(actions: [weightAction])
}
What I want: if you tap on the icon named 'Scale' you trigger a segue to ViewController C.
Also my code for the 'prepare for segue' function (for the segue to ViewController B):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailSegue"{
let rowClicked = (self.tableView.indexPathForSelectedRow?.row)!
let destVC = segue.destination as! UINavigationController
let slideVC = destVC.topViewController as! detailViewController
slideVC.araKuiken = araKuikens[rowClicked]
}
}
So how can I add a segue to ViewController C, that gets called when I tap the 'scale' button?
If you want your weightAction to trigger a segue to viewController C you will just need to perform that segue inside the handler block like so:
let weightAction = UIContextualAction(style: .normal, title: "Gewicht", handler: { (ac:UIContextualAction, view:UIView, success:(Bool) -> Void) in
self.performSegue(withIdentifier: "viewControllerC", sender: ac)
success(true)
})
Then, in your prepare code you'd want to handle this possibility as well:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailSegue"{
let rowClicked = (self.tableView.indexPathForSelectedRow?.row)!
let destVC = segue.destination as! UINavigationController
let slideVC = destVC.topViewController as! detailViewController
slideVC.araKuiken = araKuikens[rowClicked]
} else if segue.identifier == "viewControllerC" {
//Perform your preparation code here
}
}
Of course you'll still need to create the segue in the Storyboard, as you mentioned, by dragging from the yellow circle at the top of viewControllerA to viewControllerC, and giving it the proper name (I used "viewControllerC" as an example).
I saved the indexPath in a variable when the cell displays the side menu leadingSwipeActionsConfigurationForRowAt()
Then I use it in the Prepare() method
if let indexPath = self.indexPathSelected {
if segue.identifier == "IdentifierA" {
}else if segue.identifier == "IdentifierB" {
let destino = segue.destination as! VCdestinarion
destino.intLibro = Int(self.arrData[indexPath.row][1]
}
}
This worked for my.
Regards
Related
I have two ViewControllers in the first I created a tableView where I can insert just a text into a cell.
In the SecondViewController I also have a tableView with the same function, bu HOW can I make it that when I click a cell in the first tableView, I can get into a separate SecondTableView (Array).
So I'm this far, but I think the categorize function must be in the didSelectRowAt, when I click a Row.
FirstViewController:
todos: This is a String Array (I want this as the Category)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "hhh"{
//let destination = segue.destination as? UINavigationController
let vc = segue.destination as? SecondViewController
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
//label name
vc?.name = todos[indexPath.row]
self.present(vc!, animated: true, completion: nil)
tableView.deselectRow(at: indexPath, animated: true)
self.performSegue(withIdentifier: "hhh", sender: indexPath)
let indexpath = todos[indexPath.row]
print("indexpath:\(indexpath)")
print("row: \(indexPath.row)")
}
}
In the SecondViewController I have a SecondArray=[String]() these are actually the Todos.
On both ViewControllers I can insert a cell with text but don't know how to pass the data back:=?
In the comments I suggested using a UISplitViewController, as this works well with any kind of master/detail type of app. (In fact, it's an Xcode project type.)
But in case you require using a UINavigationController, here's what I to to "toggle" between two views this way:
FirstViewController:
#IBAction func showFrameVC() {
updateMaskImage()
self.performSegue(withIdentifier: "ShowSecondView", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowSecondView" {
if let vc = segue.destination as? FrameViewController {
vc.someValue = someValue
vc.firstVC = self
}
}
}
Basically, pass the instance of the first view controller along with any data you need to pass.
SecondViewController:
var someValue:String!
weak var subjectVC:FirstViewController!
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isMovingFromParentViewController {
firstVC.someValue = someValue
}
}
Here you let the navigation controller do it's thing, which is pop the second view controller off the stack after passing back the data it changed. Since you are maintaining a weak value of the first view controller, you free up that memory when the second controller is released.
In your code, you are presenting your SecondViewController in 2 ways in same function.
self.present(vc!, animated: true, completion: nil)
and
self.performSegue(withIdentifier: "hhh", sender: indexPath)
intention of both lines are same, But 2 way of implementation.
if my thinking is right you don't have to perform segue (second line of code mentioned above and also No prepare for segue method).
I have three controllers connected with segues.
Controller one is MyNotif, controller 2 is AddNotif and controller three is SelectInterval.
From controller 2 I have a segue to controller 3 and then back to controller 2.
This is because in controller 3 i will select from a tableview a value (string) which will be inserted in a field in controller 2.
When the segue from 3 to 2 is performed the controller is not dismissed. This means that if from controller 2 I press the back button (I do not use a navigation controller, the back button is a simple button. Here's the code:)
#IBAction func backBtnPressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
I will land on controller 3 instead that on controller one.
To summarise I'm trying to achieve this:
From controller 1 I go to controller 2. From here I can go to controller 3, select the string I need, perform the segue, go back to controller 2 (and till here everything works fine). Once back on controller 2 i f I click the back button i would like to go back on controller 1 (now what happens is that i go back on controller 3).
A bit complicate explain... hopefully it is a bit clear.
here's my segue code:
AddNotif:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SelectRepeatInterval" {
if let destination = segue.destination as? SelectRepeatIntervalVC {
destination.selectedRepeatingInterval = repeatingInterval
}
}
}
SelectInterval:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRow(at: indexPath)! as! SelectRepetaIntervalCell
selectedInterval = currentCell.repeatIntervalLbl.text!
performSegue(withIdentifier: "IntervalSelected", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "IntervalSelected" {
if let destination = segue.destination as? AddNotificationVC {
destination.repeatingInterval = selectedInterval
}
}
}
What you are looking for is presentingViewController https://developer.apple.com/documentation/uikit/uiviewcontroller/1621430-presentingviewcontroller
if let destination = self.presentingViewController as? AddNotificationVC {
destination.repeatingInterval = selectedInterval
}
dismiss(animated: true, completion: nil)
Here is the complete code
tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
// Get Cell Label
let currentCell = tableView.cellForRow(at: indexPath)! as! SelectRepetaIntervalCell
selectedInterval = currentCell.repeatIntervalLbl.text!
if let destination = self.presentingViewController as? AddNotificationVC {
destination.<your textfield name>.text = selectedInterval
}
dismiss(animated: true, completion: nil)
}
I have two UITableView connected through segue. I am performing segue to pass data from my firstTableView to secondTableView using tableViewCell swipe action method and saving the passed data using NSUserDefaults code works ok. But, Every time when I passed data it calls segue(I know it supposed to) and pushing to my secondTableView..I want to pass data without pushing my firstTableView to secondTableView when passing data and I have action button to access my secondController directly from mainViewController.
func tableView(_ tableView: UITableView, editActionsForRowAtIndexPath indexPath: IndexPath) -> [UITableViewRowAction]? {
let shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.normal, title: "xxxxxxxxxx") { (UITableViewRowAction, NSIndexPath) -> Void in
self.performSegue(withIdentifier: "shareSegue", sender: indexPath)
// self.dismiss(animated: true, completion: nil)
}
return shareAction
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "shareSegue") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destination as! ViewController
// your new view controller should have property that will store passed value
viewController.labelcell = (sendSelectedData as String as String)
}
//// I also tried the following method with no segue but the results pretty much same....
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC = storyboard.instantiateViewControllerWithIdentifier("secondTableView")
self.presentViewController(secondVC, animated: true, completion: nil)
Thanks in advance!!!
I want to move from one view controller to another and send userId:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("chosenPerson", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId
}
by clicking I get: "fatal error: unexpectedly found nil while unwrapping an Optional value"
what I do wrong?
If you have given segue in StoryBoard DON'T Call this self.performSegueWithIdentifier("chosenPerson", sender: self) method in didSelectItem
If you have given segue in storyboard override func prepareForSegue - this method calls first after that didSelectItem calls
Please refer storyBoard once (below Image for Sample)
I think problem is in self.usersArray[indexPath.row].userId May this returns nil
Swift2:
self.performSegueWithIdentifier("chosenPerson", sender: self)
Swift3:
self.performSegue(withIdentifier: "chosenPerson", sender: self)
Swift2:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destinationViewController as? chosenPersonViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()!
let indexPath = indexPaths[0] as NSIndexPath
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
Swift3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "chosenPerson" {
let chosenPerson = segue.destination as! chosenPersonViewController
if let indexPath = collectionView.indexPathForSelectedItem {
chosenPerson!.userID = self.usersArray[indexPath.row].userId //May it found nil please re - check array values
}
}
}
When performing the segue, pass the indexPath as the sender and try using this switch statement. If you see "unknown segue" printed out when you select a cell, the destination controller is not of type chosenPersonViewController.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("chosenPerson", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch (segue.destinationViewController, sender) {
case (let controller as chosenPersonViewController, let indexPath as NSIndexPath):
controller.userID = usersArray[indexPath.row].userId
default:
print("unknown segue")
break
}
}
One possible issue could be that in your storyboard you have not set the identifier for your segue to be "chosenPerson". To fix this first make sure you have a segue between your first and second view controllers, which can be created by control dragging one from one view controller to another.
Then make sure the segue has an identifier, specifically: "chosenPerson". To do this: click on the segue between the first two view controllers, then navigate to the attributes tab, and then set the identifier box to be "chosenPerson". Save the storyboard with your changes and now you should be able to call prepareForSegue with that identifier and not experience a fatal error.
I'm making an app that is sending information about text inside of cells to a WebViewController using swipe actions. The swipe action is:
let sendToWebsite = UITableViewRowAction(style: .Default, title: "Website")
{ (action, indexPath) in
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
}
sendToWebsite.backgroundColor = UIColor.blueColor()
return [sendToWebsite]
}
This works fine but I also have two segues coming from the same View Controller, to two other VC's. The first segue(recipeDetail) is when you tap directly on the cell and works fine, but the second segue(yourSegueIdentifier) is a button that appears when you activate the slide action on the cell and does't work.
the segues:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "recipeDetail") {
let indexPath = self.tableView!.indexPathForSelectedRow
let destinationViewController: DetailViewController = segue.destinationViewController as! DetailViewController
destinationViewController.recipe = recipes[indexPath!.row]
}
else if segue.identifier == "yourSegueIdentifier"
{
let indexPath = self.tableView!.indexPathForSelectedRow
let nextVC: WebViewController = segue.destinationViewController as! WebViewController
nextVC.recipe = recipes[indexPath!.row]
}
}
On the line
nextVC.recipe = recipes[indexPath!.row]
indexPath is coming out as nil and giving the following error message
Well it looks like on the swipe action, the tableView doesn't register the "indexPathForSelectedRow" method.
What you could alternatively do is setup a global swipeIndex variable
class ViewController: UIViewController{
var swipeIndex : Int!
//Code, code, code...
and then set it once the swipe action is called.
let sendToWebsite = UITableViewRowAction(style: .Default, title: "Website")
{ (action, indexPath) in
self.swipeIndex = indexPath.row
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
}
sendToWebsite.backgroundColor = UIColor.blueColor()
return [sendToWebsite]
}
and then:
else if segue.identifier == "yourSegueIdentifier"
{
let indexPath = self.tableView!.indexPathForSelectedRow
let nextVC: WebViewController = segue.destinationViewController as! WebViewController
nextVC.recipe = recipies[self.swipeIndex]
}
}