Dismiss modal from a view in a tab bar view - swift

How can I dismiss a modal view opened from a view in a tab bar view and stays on that view?
I have a tab bar view after login in and there are two views on the tab view (Clients and Profile).
On clients I have a list of clients and I can open another view that shows invoices.
Tapping on an invoice, it shows me the details of a particular invoice.
On this view, there is an actionView with some buttons.
One of those button is "Make Payment".
When tapped on Make Payment, a modal windows is shown.
However, when I tap on a cancel button, it removes all the views and goes back to the login view (initial view)
Invoice View
#IBAction func showActionAlert(_ sender: Any) {
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let payButton = UIAlertAction(title: "Make Payment", style: .default, handler: { (action) -> Void in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "MakePaymentViewController")
self.present(controller, animated: true, completion: nil)
})
let voidButton = UIAlertAction(title: "Void", style: .destructive, handler: { (action) -> Void in
})
let deleteButton = UIAlertAction(title: "Delete", style: .destructive, handler: { (action) -> Void in
})
let cancelButton = UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in })
alertController.addAction(payButton)
alertController.addAction(voidButton)
alertController.addAction(deleteButton)
alertController.addAction(cancelButton)
self.navigationController!.present(alertController, animated: true, completion: nil)
}
Modal View
#IBAction func cancelButton(_ sender: Any) {
let tmpController :UIViewController! = self.presentingViewController;
self.dismiss(animated: false, completion: {()->Void in
tmpController.dismiss(animated: true, completion: nil);
});
}

I changed the cancelButton action and it worked:
#IBAction func cancelButton(_ sender: Any) {
dismiss(animated: true, completion: nil)
}

The controller you're presenting it from is your navigationController in which your navigation stack is.
If you present several viewControllers from your navigationController and then dismiss all the presented Controllers from the parent/presentingViewController(which is navigationController) all viewControllers that are presented on are dismissed.
Instead of presenting it like this :
self.navigationController!.present(alertController, animated: true, completion: nil)
do this
self.present(alertController, animated: true, completion: nil)
And while dismissing do:
self.dismiss(animated: true, completion: nil)

Related

Alert not showing on the modal that is presenting

On a view Controller when I click on the guard button -->
#IBAction func guardTapped(_ sender: Any) {
let vc = guardViewController.instanceFromNib()
vc.modalPresentationStyle = .overCurrentContext
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.present(vc, animated: true, completion: nil)
}
}
So In this guardViewController which is a presenting modal, I want to show an alert message when I click on the close button on guardViewController.
#IBAction func closeTapped(_ sender: Any) {
let alert = UIAlertController(title: "Alert", message: "Are You Sure", preferredStyle: .alert)
let proceedAction = UIAlertAction(title: "Proceed", style: .destructive) { (action) in
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.dismiss(animated: true)
}
}
alert.addAction(proceedAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
//
}
alert.addAction(cancelAction)
if let popoverController = alert.popoverPresentationController {
popoverController.sourceView = sender as? UIView
popoverController.sourceRect = CGRect(x: (sender as AnyObject).bounds.midX, y: (sender as AnyObject).bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = [.any]
}
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.present(alert, animated: true, completion: nil)
}
}
Try presenting simple Alert with this Alert helper:
struct Alert {
static func showErrorAlertWithOk(on vc: UIViewController, withTitle: String, andMessage: String) {
let alert = UIAlertController(title: withTitle, message: andMessage, preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .cancel) {_ in }
alert.addAction(action)
vc.present(alert, animated: true)
}
}
Then use is as folows:
Alert.showErrorAlertWithOk(on: yourViewController, withTitle: "SampleAlert", andMessage: "YourMessage")

Unable to pass image between view controllers

As asked on the question. On my first VC, I have set up a function that passes an image to another VC as follows.
#objc func imageTapped(tapGestureRecognizer1: UITapGestureRecognizer) {
let passimage = tapGestureRecognizer1.view as! UIImageView
let alertController = UIAlertController(title: "...", message: "...", preferredStyle: UIAlertController.Style.alert)
let ok = UIAlertAction(title: "...", style: UIAlertAction.Style.default, handler: {(action) -> Void in
self.performSegue(withIdentifier: "Shop", sender: self)
print("image tapped")
let sb = self.storyboard?.instantiateViewController(withIdentifier: "shopVC") as! shopVC
sb.loadimage = passimage.image
self.present(sb, animated: true, completion: nil)
})
alertController.addAction(ok)
alertController.addAction(UIAlertAction(title: "取消(留在此版面)", style: UIAlertAction.Style.cancel, handler: nil))
self.present(alertController, animated: true, completion: nil)
}
whilst on the other VC, I've set up an Image View which would read the image as shown here.
class shopVC: UIViewController {
#IBOutlet weak var clothimage: UIImageView!
var loadimage: UIImage?
override func viewDidLoad() {
clothimage.image = loadimage
super.viewDidLoad()
}
I know the "passimage.image" is what I want as it shows up in the debugging window - I can't seem to place it in the second VC.
for change ViewController you use two Option same Time, When used individually, each:
// optionOne
self.performSegue(withIdentifier: "Shop", sender: self)
print("image tapped")
// optionTwo
let sb = self.storyboard?.instantiateViewController(withIdentifier: "shopVC") as! shopVC
sb.loadimage = passimage.image
self.present(sb, animated: true, completion: nil)
if use Option One, you must override below function from firstVC and set image directly:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? shopVC {
vc.image = yourImage
}
}
and if you use present for show ShopVC nothing change code just comment performSegue function.
That means only the following code:
let sb = self.storyboard?.instantiateViewController(withIdentifier: "shopVC") as! shopVC
sb.loadimage = passimage.image
self.present(sb, animated: true, completion: nil)
Need to call super.viewDidLoad() first and then setting up clothimage

While present navigation then presented viewcontroller bar button not coming, why in swift

my viewcontroller flow will be like below:
navigationcontroller -> logoutviewcontroller ->(present)
viewcontroller -> (present) logoutviewcontroller (bar button coming)
|
loginviewcontroller
|
(present) logoutviewcontroller (bar button not coming)
logoutVC code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "logout", style: .plain, target: self, action: #selector(handleLogout))
}
#objc func handleLogout(){
let vc = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.present(vc, animated: true, completion: nil)
}
loginVC code: when presenting logoutVC coming but bar button not coming.. why
#IBAction func loginButn(_ sender: Any) {
guard let email = emailTf.text, let password = passwordTf.text
else {
print("form is not valid")
return
}
Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in
if error != nil{
print("login adding error: \(String(describing: error))" as Any)
return
}
print("login sucessfully")
let vc = self.storyboard?.instantiateViewController(withIdentifier: "LogOutViewController") as! LogOutViewController
self.present(vc, animated: true, completion: nil)
})
}
please suggest here with code
If by bar button you mean the navigationController's navigationBar, you don't need to present the ViewController but you need to use
self.navigationController?.pushViewController(vc, animated: true)

NavigationController doesn't see right bar button item

I'm trying to understand presentation view controllers by allowing the user to add new outcomes of a fortune telling app. When the user taps on "Add New Outcome" on the top right of the navigation bar a new view controller pops up and this is where the user can enter a new outcome. I'm trying to add a done button to the top right of the presentation controller but I'm getting an error saying Value of type 'UINavigationController?' has no member 'rightBarButtonItem'.
I thought it was because of referencing the topViewController was the problem but I'm doing this all in 1 ViewController.
#IBAction func actionButtonTapped(_ sender: UIBarButtonItem) {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "AddNewOptionController")
viewController.modalPresentationStyle = .popover
let popover : UIPopoverPresentationController = viewController.popoverPresentationController!
popover.barButtonItem = sender
popover.delegate = self
present(viewController, animated: true, completion: nil)
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .fullScreen
}
func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(ViewController.dismissViewController))
//error below
navigationController.topViewController?.navigationController.rightBarButtonItem = doneButton
return navigationController
}
func dismissViewController() {
self.dismiss(animated: true, completion: nil)
}
Instead of:
navigationController.topViewController?.navigationController.rightBarButtonItem = doneButton
Try:
navigationController.topViewController?.navigationItem.rightBarButtonItem = doneButton
you can use this code:
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named:"YOUR_IMAGE_NAME"), style: .plain, target: self, action: #selector(YOUR_FUNCTION))
hope this work for you

Storyboard or segue from ViewController to Tabbar Controller

I want to implement a segue / storyboard in a button FROM View Controller TO tab bar controller (Home) in swift 3
My storyboard
This is my sign in code
#IBAction func LogIn(_ sender: Any) {
if self.emailTextfield.text == "" || self.passwordTextfield.text == "" {
let alertController = UIAlertController(title: "Error", message: "Please enter an email and password.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
FIRAuth.auth()?.signIn(withEmail: self.emailTextfield.text!, password: self.passwordTextfield.text!) { (user, error) in
if error == nil {
print("You have successfully logged in")
//this is my storyboard but it gives me black screen
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
} else {
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
I tried using storyboard
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.present(vc!, animated: true, completion: nil)
i tried using segue
self.performSegue(withIdentifier: "Home", sender: self)
both gives me black screen. why? I have a clarification also. where should i connect my segue, is it in the tab bar controller(grey) or to the first TAB controller?
Try Below step,
1) Create new function in AppDelegate class
func LoginNav()
{
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateViewControllerWithIdentifier("MainTab") as! tabbarControllerViewController // U have to create tabbarControllerViewController for ur TabBarView
self.window?.rootViewController = mainViewController
self.window?.makeKeyAndVisible()
}
2) Then call that func from any viewcontroller like below
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.LoginNav()