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
}
Related
I am currently unable to dismiss a viewcontroller and at the same time make the application move to a different controller without experiencing a few bugs. What my code does currently is when the timer 'secondsRemaining' hits zero it will dismiss the current viewcontroller it is on and will show the previous viewController that is displayed underneath the current viewcontroller being the 'homeScreenViewController'. Because of this it will not call the code- self.performSegue(withIdentifier: "gameScreenToHighscore", sender: self).
Current code:
#objc func updateTimer() {
if secondsRemaining > 0 {
secondsRemaining -= 1
timerLabel.text = "Timer:\(secondsRemaining)"
print(secondsRemaining)
} else {
self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "gameScreenToHighscore", sender: self)
}
}
I think the best approach is that you handle the navigation in the parent ViewController, You can achieve this by making delegate.
In the ChildViewController:
#protocol ModalVCDelegate {
func navigateToTheSecondVC()
}
class ModalViewController {
weak delegate: ModalVCDelegate!
}
and you should call the delegate method when the timer has done.
delegate?.navigateToTheSecondVC()
And Also in the ParentViewController, you should set the delegate:
childVC.delegate = self
present(childVC, animated: true, completion: nil)
and then:
extension MainViewController: ModalVCDelegate {
func navigateToTheSecondVC {
dismiss(animated: true, completion: {
self.performSegue(withIdentifier: "gameScreenToHighscore", sender: self)
})
}
}
I need to present a modal VC that sets a property in my presenting VC, and then I need to do something with that value back in the presenting VC. I have to be able to pass pointers to different properties to this function, so that it's reusable. I have the code below (KeyPickerTableViewController is the modal VC).
It should work, except not, because the line after present(picker... gets executed immediately after the picker is presented.
How do I get my presenting VC to "wait" until the modal VC is dismissed?
#objc func fromKeyTapped(_ button: UIBarButtonItem) {
print("from tapped")
setKey(for: &sourceKey, presentingFrom: button)
}
#objc func toKeyTapped(_ button: UIBarButtonItem) {
print("from tapped")
setKey(for: &destKey, presentingFrom: button)
}
fileprivate func setKey(for key: inout Key!, presentingFrom buttonItem: UIBarButtonItem) {
let picker = KeyPickerTableViewController()
picker.delegate = self
picker.modalPresentationStyle = .popover
picker.popoverPresentationController?.barButtonItem = buttonItem
present(picker, animated: true, completion: nil)
if let delKey = delegatedKey {
key = delKey
}
}
You could use delegate pattern or closure.
I would do the following
1. I would not use inout pattern, I would first call the popover and then separately update what is needed to be updated
2. In KeyPickerTableViewController define property var actionOnDismiss: (()->())? and setting this action to what we need after initialisation of KeyPickerTableViewController
I could show it in code, but the abstract you've shown is not clear enough to come up with specific amendments. Please refer the illustration below.
import UIKit
class FirstVC: UIViewController {
var key = 0
#IBAction func buttonPressed(_ sender: Any) {
let vc = SecondVC()
vc.action = {
print(self.key)
self.key += 1
print(self.key)
}
present(vc, animated: true, completion: nil)
}
}
class SecondVC: UIViewController {
var action: (()->())?
override func viewDidLoad() {
onDismiss()
}
func onDismiss() {
action?()
}
}
While presenting VC, add dismissing modal VC action in its completion handler, so that Viewcontroller will be presented after dismissal is completed
present(picker, animated: true, completion: { (action) in
//dismissal action
if let delKey = delegatedKey {
key = delKey
}
})
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()
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.