Swift - UIStoryboardSegue pop up ViewController programatically - swift

I have UIButton attached to navigationBar programatically:
catButton.addTarget(self, action: "oc:", forControlEvents: .TouchUpInside)
var catBarButton:UIBarButtonItem = UIBarButtonItem(customView: catButton)
self.navigationItem.setRightBarButtonItem(catBarButton, animated: false)
when function oc() is triggered I want to popover view controller
let segue = UIStoryboardSegue(identifier: "oc", source: self, destination: MDComDBCatsTVC())
prepareForSegue(segue, sender: but)
but this doesn't open MDComDBCatsTVC.. How to do it programatically because I can't drag from button in my storyboard because my button is added programatically

I can't drag from button in my storyboard because my button is added programatically
You can create the segue in the storyboard by dragging from the view controller icon to the target view controller. This segue can then be used programmatically.
Click on the segue to assign an identifier in the Attributes inspector panel. The segue can then be accessed programmatically using this identifier.
Xcode will insist that popover segues have an anchor. The error message is “Popover segue with no anchor”. This can be resolved in the Attributes inspector - the Anchor property. Drag from the circle to your view.
In the action for your programmatically created button you will then be able to access the segue using eg:
func buttonAction(sender:UIButton!)
{
performSegueWithIdentifier("popoversegue", sender: self)
}
( ... or more likely something more robust using if let etc)

you can use dynamic popup views like that
let vc = storyboard.instantiateViewControllerWithIdentifier("myPopupView") as! myPopupViewViewController
self.presentViewController(vc, animated: true, completion: nil)

If you want to do this via storyboard connect your view controllers in storyboard with segue (drag from first view controller to second one, it doesn't mean to drag from button only) name that segue "oc" then in button action perform segue like following
performSegueWithIdentifier("oc", sender: but)

Related

Programmatically press back button for UIViewController with UITableView iOS swift

I have a UIViewController that implements UITableViewDelegate, UITableViewDataSource and that contains a UITableView as a member variable. When a user click on one of the rows of that table, the app performs a storyboard segue to open the detail view controller. That detail view controller of course has a button in the top left of the screen that is the "back" button to go back up to the UIViewController with the UIViewTable.
So, suppose that I want to programmatically "click" that back button. How exactly would I do that in swift? This is the most recent version of swift (swift 4?) in XCode 10.1.
UPDATE:
So here is how I solved this. As the answers below show, it is possible to use self.navigationController?.popViewController(animated: true) to just return to the previous view controller. What I discovered I also wanted to do, however, was to call a specific method in that view controller so that it executed a certain behavior once it got shown. It turns out that is also possible, but in my case it was a bit tricky, since that prior view controller was actually a UITabBarController. Therefore I had to get the ViewController that I was interested in from the UITabBarController. I did it like this:
let numvc = navigationController!.viewControllers.count
let tvc:UITabBarController = navigationController!.viewControllers[numvc-2] as! UITabBarController
let my_vc: MyCustomVC = tvc.viewControllers![0] as! MyCustomVC
my_vc.some_function()
Here of course MyCustomV is my custom view controller class and some_function() is the method I want to call on that class. Hope this helps someone.
When You run a segue you perform a "pushViewController" method to the next view, so if you want to go back to the previous view programmatically you just have to do is pop the last view like so:
self.navigationController?.popViewController(animated: true)
UPDATE
You just need the if statement if you have multiple segues from that viewController, if not, you can delete and just cast the next view as you wish and set the properties, let the autocomplete write the *prepare(for segue... * method for you, so You don't run into any problems
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourSegueName" {
let destinationVC = segue.destination as! CustomViewController
destinationVC.labelExample.text = "Some text I'm sending"
}
}
Are you sure you need to "click" the button?
If all you need is to dismiss details view controller, you can just call navigationController?.popViewController(animated: true)
Or if you want to deal directly with button, you can tell it to send its actions: backButton.sendActions(for: .touchUpInside)
Or if you absolutely need to show button clicking animation, then you will need something like this (you should play and choose suitable delay):
backButton.isHighlighted = true
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) {
backButton.isHighlighted = false
backButton.sendActions(for: .touchUpInside)
}

Performing segue with UINavigationController (without IBAction)

It's easier to show you a drawing and then explain.
Dashboard Storyboard
I have 2 separate UIViewControllers (i've included just one in the drawing, the other is irrelevant) embedded in container view called ContainerViewController.
Post Storyboard
NewPostViewController shows a UIButton that presents TextPostViewController. As you can see, all of them are embedded in UINavigationControllers. Now, once the completion block of the new post is being called, I have to present the ContainerViewController and it needs to handle it's own logic. The problem is that it's embedded in UINavigationController and once I present it, the UITaBbar is hidden.
I tried to do this:
self.performSegue(withIdentifier: "TextPostToNavContainerVC", sender: nil)
The transition is successful but I'm losing the UITabBar, even though in the DashboardViewController and the ContainerViewController I called:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tabBarController?.tabBar.isHidden = false
}
What am I doing wrong or is there are better way to do that?
You should instantiate the tab bar controller. not the view controller.
Imagine you're putting a initial view controller ahead of your tab bar controller. Making your tab bar not being pushed
If I undestand it correctly.
You are doing this
Segue connect to a view controller
But you should actually do this Segue connected to a tab bar controller
You can try to add it as a child to control it's frame like this
let textPost = self.storyboard?.instantiateViewController(withIdentifier: "containerID") as! TextPostToNavContainerVC
textPost.view.frame = CGRect(x:20,y:0,width:self.view.frame.width,height:self.view.frame.height-50)
self.view.addSubview(nvc.view)
self.addChildViewController(textPost)
textPost.didMove(toParentViewController: self)

macOS - Transition between view controllers like iOS, dont open separate window

Im building an app in swift for macOS, and I have a button on my initial view controller that I want to display a different view controller. I ctrl dragged from that button to the new view controller, and all of the segue options display the new view controller as a new window, rather that replacing the initial view. How can I make this button transition view controllers similar to how it works in iOS apps?
You can first make your segue to the 2nd view controller and then create an IBAction from your button where you call
self.dismiss(animated: true, completion: {})
within it. By doing this your initial view controller will no longer exist.
More detailed:
Segue from your button to the second view controller (ctrl drag)
Make an IBAction by ctrl drag from your button to the view controllers code
Put this into your IBAction:
self.dismiss(animated: true, completion: {})
Now it should look something like this:
#IBAction func dismissView(_ sender: Any) {
self.dismiss(animated: true, completion: {})
}
By clicking on your button your application go to the next view controller and the initial view controller will be dismissed.

Perform segue and don't show "Back" button on the destination view controller

I would like to seque programmatically to a "setup-VC" when the initial setup is not done. This works, BUT in this case I don't want to show the back button on the "setup-VC".
What I've done till now:
I've created two VC. (main-VC and setup-VC)
The code of main-VC:
...
if InitialSetupIsDone == true {
println("Loading the data...") //PPP
} else {
println("Segue to setup screen...") //PPP
self.performSegueWithIdentifier("segueToSetup", sender: self)
}
...
// Pull any data from the view controller which initiated the unwind segue.
#IBAction func segueToSetup(sender: UIStoryboardSegue)
{
let sourceViewController: AnyObject = sender.sourceViewController
}
In the main-VC I've created an unwind-segue ("EXIT"-action? - red icon at the top of the VC) and named it "segueToSetup".
At last point I've connected the "setup-VC" with the "main-VC" while dragging an segue from main-VC (yellow Icon top left) to the setup VC.
Then it would look like this:
(The upper connection goes directly from setup sign to the "setup-VC")
The goal for me now would be to kind of "hide" the back button in "setup-VC" while the initial setup is not done. Maybe I've don't create the unwind segue right... !? Thx
Write this line in destination VC viewDidLoad
navigationController?.navigationItem.setHidesBackButton(true, animated: true)
In viewWillAppaer method also write this
navigationController?.navigationItem.setHidesBackButton(true, animated: true)
This disabled the button for me:
let backButton = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.Plain, target: navigationController, action: nil)
navigationItem.leftBarButtonItem = backButton

iPhone popup menu like iPad popover?

How can i implement this popup menu in iphone app like a popover in ipad?
EDIT: This is the best at moment: https://github.com/runway20/PopoverView
iOS 8 and later
Beginning with iOS 8, you can use UIPopoverPresentationController for iPhones in addition to iPads.
Setup
Add a UIBarButtonItem to your main View Controller.
Add another View Controller to the storyboard. Change it to the size that you want the popover to be and add any content that you want it to have. For my example I just added a UILabel. If you want a whole menu, then just add a table view or list of buttons.
Add a segue from the bar button item to the view controller that you will use as the popover. Rather than show, choose Present as Popover.
Select the segue in the storyboard and set the identifier to popoverSegue (or whatever string you called it in the code).
In the Attributes inspector for the popover view controller, check Use Preferred Explicit Size and confirm that it is the size you want it to be.
Code
This is the code for the main view controller that has the bar button item in it.
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "popoverSegue" {
let popoverViewController = segue.destinationViewController
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
popoverViewController.popoverPresentationController!.delegate = self
}
}
// MARK: - UIPopoverPresentationControllerDelegate method
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
// Force popover style
return UIModalPresentationStyle.None
}
}
Popover at an arbitrary anchor point
If you want to set the popover to appear somewhere besides a bar button item (on a UIButton for example) then you need to set the sourceView and sourceRect. See this answer for details.
Further reading
The above example comes mostly from the first link.
iPad Style Popovers on the iPhone with Swift
iOS 8 Popover Presentations
UIPopoverPresentationController on iOS 8 iPhone
General overview of popup options in iOS
Have a look at the iPhone UIPopoverController implementation: WEPopover
On iPhone you would generally use a UIActionSheet for a stack of buttons like that. It slides up from the bottom, rather than popping up next to the button, but that's the standard behavior on iPhone.
There is one that is even better than WEPopover. Developed by a company called 50pixels, it is called FPPopover.
You can download FPPopover at https://github.com/50pixels/FPPopover
You would have to manually instantiate a UIView using a custom background image or drawing with transparency, add some UIButtons (or other type of custom view) on top, and also somehow handle all touches outside that view.
Note that is is non-standard UI. An actionsheet would be more HIG compliant.
To get a popover from a right side bar button item on a navigation controller that is part of a tableview controller, the following worked for me for Swift 4 and Xcode 9.
Follow the steps in Suragch answer above (as edited by the Community.)
Do not implement the Segue as shown in the answer above. For some reason, the segue causes the popover to go full screen despite setting the explicit size.
Give your popover view controller a title in Attributes Inspector
Add the following code in the TableView controller where the popup will show.
Modify the string identifier (the one here is referencing a Constant.swift file)
Modify "as! FilterVC" to use the title of the your popover view controller.
/// Shows a filter popover view
#IBAction func filterBtnPressed(_ sender: UIBarButtonItem) {
let popover = storyboard?.instantiateViewController(withIdentifier: FILTER_VC) as! FilterVC
popover.modalPresentationStyle = UIModalPresentationStyle.popover
popover.popoverPresentationController?.backgroundColor = UIColor.green
popover.popoverPresentationController?.delegate = self
popover.popoverPresentationController?.backgroundColor = ColorPalette.Blue.Medium
popover.popoverPresentationController?.sourceView = self.view
popover.popoverPresentationController?.sourceRect = CGRect(x: self.view!.bounds.width, y: 0, width: 0, height: 0)
popover.popoverPresentationController?.permittedArrowDirections = .up
self.present(popover, animated: true)
} }
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
You can check WYPopoverController: https://github.com/sammcewan/WYPopoverController
The screenshot above is not a UIActionSheet. It looks like a simple UIView subclass with custom UIButtons on top of it. So go ahead and create the subclass according to your needs and then add it as a subview to your view every time you need it.