I have 2 view controllers which should be swapped according to userinput. So, I want to switch the views programatically based on the input I get from a text file.
Algorithm :
if(input == 1)
{
Go to View Controller 1
}
else if(input ==2)
{
Go to View Controller 2
}
Any help on how to click the button programmatically or load that particular viewcontroller with input?
To fire an event programmatically you need to call sendActionsForControlEvent
button.sendActionsForControlEvents(.TouchUpInside)
--
Swift 3
button.sendActions(for: .touchUpInside)
Or you can just put all the logic that you perform when a button gets clicked in a separate method, and call that method from your button's selector method.
#IBAction func someButtonPressed(button: UIButton) {
pushViewControllerOne()
}
#IBAction func someButtonPressed(button: UIButton) {
pushViewControllerTwo()
}
func pushViewControllerOne() {
let viewController = ViewControllerOne(nibName: "ViewControllerOne", bundle: nil)
pushViewController(viewController)
}
func pushViewControllerTwo() {
let viewController = ViewControllerOne(nibName: "ViewControllerTwo", bundle: nil)
pushViewController(viewController)
}
func pushViewController(viewController: UIViewController) {
navigationController?.pushViewController(viewController, animated: true)
}
Then instead of invoking programatically invoking a button press, just call the method pushViewControllerOne() or pushViewControllerTwo()
Related
In my NSDocument subclass I instantiate an NSPopover, with .semitransient behaviour, and show it:
popover.show(relativeTo: rect, of: sender, preferredEdge: .maxX)
popover is declared locally. A button method in the popover controller calls:
view.window?.close()
The popover closes, but I have become aware that it remains in memory, deinit() is never called and the NSApp.windows count increases, whereas if I dismiss it by pressing escape or clicking outside it, deinit is called and the windows count doesn't increase.
If I set the window's .isReleasedWhenClosed to true, the windows count doesn't increase, but deinit is still not called.
(Swift 3, Xcode 8)
You have to call performClose (or close) on the popover, not the window.
Thanks -DrummerB for your interest. It has taken me some time to get around to making a simple test application I might send you, and of course it wasn't a document-based one as mine was, and that seemed to be clouding the issue. My way of opening the popover was based on an example I'd recently read, but can't now find or I'd warn people. It went like this:
let popover = NSPopover
let controller = MyPopover(...)! // my convenience init for NSViewController descendant
popover.controller = controller
popover.behaviour = .semitransient // and setting other properties
popover.show(relativeTo: rect, of: sender, preferredEdge: .maxX)
Here's the improved way I've come across:
let controller = MyPopover(...)! // descendant of NSViewController
controller.presentViewController(controller,
asPopoverRelativeTo: rect, of: sender, preferredEdge: .maxX,
behavior: .semitransient) // sender was a NSTable
In the view controller, the 'Done' button's action simply does:
dismissViewController(self)
which never worked before. And now I find the app's windows list doesn't grow, and the controller's deinit happens reliably.
I would suggest doing the following:
Define a protocol like this
protocol PopoverManager {
func dismissPopover(_ sender: Any)
}
In your popoverViewController (in this example we are displaying a filter view controller as a popover) add a variable for the popoverManager like this
/// Filter shown as a NSPopover()
class FilterViewController: NSViewController {
// Delegate
var popoverManager: PopoverManager?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
// Bind this to the close button or action on your popover view controller
#IBAction func closeAction(_ sender: Any) {
self.popoverManager?.dismissPopover(sender)
}
...
}
Now in your viewController that you show the popover from add an extension like this
extension MainViewController: NSPopoverDelegate, PopoverManager {
#IBAction func setFilter(_ sender: AnyObject) {
self.showFilterPopover(sender)
}
func showFilterPopover(_ sender: AnyObject) {
let storyboard = NSStoryboard(name: "Filter", bundle: nil)
guard let controller = storyboard.instantiateController(withIdentifier: "FilterViewController") as? FilterViewController else {
return
}
// Set the delegate to self so we can dismiss the popover from the popover view controller itself.
controller.popoverManager = self
self.popover = NSPopover()
self.popover.delegate = self
self.popover.contentViewController = controller
self.popover.contentSize = controller.view.frame.size
self.popover.behavior = .applicationDefined
self.popover.animates = true
self.popover.show(relativeTo: sender.bounds, of: sender as! NSView, preferredEdge: NSRectEdge.maxY)
}
func dismissPopover(_ sender: Any) {
self.popover?.performClose(sender)
// If you don't want to reuse it
self.popover = nil
}
}
I've got 4 ViewControllers attached to a NavigationController. The order of them is 1->2->3->4. When the user presses the back button on 4, I'd like them to be redirected to 2 instead of 3. At the same time, I'd also like the user to be directed back to 2 when the back button is pressed on 3. Is this possible? Thanks in advance.
Of course you can do this. Simply create the left bar button on 4th ViewController. and on that button action pop to 2nd viewcontroller
if let viewcontroller = self.navigationController?.viewControllers[1] where viewcontroller.isKindOfClass(YourController) {
self.navigationController?.popToViewController(viewcontroller, animated: false) }
if let vc = self.viewControllerWithClass(YourVC.self) {
self.popToViewController(vc, animated: true)
}
extension UINavigationController {
func viewControllerWithClass(_ aClass: AnyClass) -> UIViewController? {
for vc in self.viewControllers {
if vc.isMember(of: aClass) {
return vc
}
}
return nil
}
}
You can check for the controller in navigation stack.
let controllers = navigationController!.viewControllers.reverse()
for controller in controllers
{
if controller.isKindOfClass(YourController)
{
self.navigationController?.popToViewController(controller, animated: true)
return
}
}
I have an issue where dismissViewController method is not actually doing anything. My code is as follows:
import UIKit
class CameraController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
....
#IBAction func dismissPhotoPicker(sender: UIButton!) {
print("in the function")
self.dismissViewControllerAnimated(true, completion: nil)
}
}
No errors are thrown when running, click on the button does trigger the method (I put a print statement in the function)
There are 2 buttons "Back", which calls that method, and another one called "Open Image Picker", which opens the Image Picker.
My storyboard starts with a TabBarViewController, I set up a segue such that when clicking on the "Camera" button, it switches to the "CameraViewController", which is associated with the custom class CameraController (which I've specified in my Storyboard.xib file)
Can you do something like this?
yourView:UIView {
// do something
}
yourMainController:UIViewController {
let view = yourView()
func showView() {
self.view.addSubview(view)
}
func hideView() {
view.removeFromSuperView()
}
}
Try this code:
if self.isBeingPresented() {
// being presented
print("being present, going to dismiss..")
self.dismissViewControllerAnimated(true, completion: nil)
} else if self.isMovingToParentViewController() {
// being pushed
print("being pushed, going to pop..")
if let navController = self.navigationController {
navController.popViewControllerAnimated(true)
}
} else {
// simply showing again because another VC was dismissed
}
I would like to perform some actions when a user presses the "Back" button on my Navigation Controller. Is there a Swift function that is called when this happens?
Try this (copied and pasted from manecosta)
Replacing the button to a custom one as suggested on another answer is possibly not a great idea as you will lose the default behavior and style.
One other option you have is to implement the viewWillDisappear method on the View Controller and check for a property named isMovingFromParentViewController. If that property is true, it means the View Controller is disappearing because it's being removed (popped).
Should look something like:
override func viewWillDisappear(animated : Bool) {
super.viewWillDisappear(animated)
if (self.isMovingFromParentViewController()){
// Your code...
}
}
Here is the link to the other question
override func viewWillDisappear(animated: Bool) {
// Do Your Lines of Code ...
}
Everytime when back button or Done is pressed or a view is popped out this function is called.. you need to override this..
Try to call this
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
if self.isMovingFromParent {
print("isMovingFromParent()") // dismiss for push viewController
}
if self.isBeingDismissed {
print("isBeingDismissed()") // dismiss for modal that doesn't has navigationController
}
if self.navigationController?.isBeingDismissed ?? false {
print("navigationController?.isBeingDismissed()") // dismiss for modal that has navigationController
}
}
Try this:
override func willMoveToParentViewController(parent: UIViewController?) {
if parent == nil {
// Back button Event handler
}
}
Swift 5
"viewWillDisappear" call Every time for forward or backward.
But if you add this check it's call only when back from controller.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParent {
print("Only back action")
}
}
I try to show a UIView when a button is clicked, but it seems that the UI can't get updated, because the button also activates a segue. When I delete the segue, the UI is updated and my UIView is drawn.
Can anyone help me on how to solve this problem?
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject!) -> Bool {
if identifier == "mySegue" {
if(myLocation == nil) {
/* Rest of code */
return false
}
else {
// These properties need to be set
box.hidden = false
actInd.startAnimating()
return true
}
}
return true
}
#IBAction func startComputing(sender: UIButton) {
//When I put the properties, nothing happens,
//but something like print("Button pressed") does happen.
}
Thanks in advance!
From what I understand, the view is within the view controller window hierarchy, so I'd do this without using segues:
#IBAction func startComputing(sender: UIButton) {
UIView.transitionWithView(self.yourView, duration: 0.5, options:UIViewAnimationOptions.TransitionFlipFromLeft, animations: {
}, completion: nil)
}
This will present your view when the button is clicked. Inside the block you can do the rest like updating UI etc.