Add a "Done" button to dismiss a programmatically created UIViewController - ios

I'm a swift newbie and made a demo app which has a UIViewController and UITableViewController in the Storyboard. The UIViewController has a Collection View and an embedded navigation controller. On tapping a collection view cell, the app segues to the UITableViewController. I can come back to my UIViewController from the UITableViewController as well. All this works well. Now, some of the rows in my UITableViewController have URLs. On tapping a URL, I programmatically create a webview inside a UIviewcontroller and get the URL to load in it. The issue is that I can't dismiss the webview and get back to my UITableViewController after this. This is the code I have in my UITableViewController class :
// When user taps a row, get the URL and load it in a webview
let mywebViewController = UIViewController()
let webView = UIWebView(frame: mywebViewController.view.bounds)
webView.loadRequest(NSURLRequest(URL: url)) // url from the row a user taps
mywebViewController.view = webView
self.navigationController!.presentViewController(mywebViewController, animated: true, completion: nil)
How can I add a Done button to this programmatically created UIviewcontroller to dismiss the webview and get back to my UITableViewController

You can wrap the mywebViewController in a UINavigationController then set the rightBarButtonItem to UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss") like this:
let navController = UINavigationController(rootViewController: mywebViewController)
mywebViewController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss")
self.navigationController!.presentViewController(navController, animated: true, completion: nil)
and add a dismiss function in your UITableViewController:
func dismiss() {
self.dismissViewControllerAnimated(true, completion: nil)
}

Add done button to your presented ViewController and make an action for it.
To dismiss ViewController try this :
self.dismissViewControllerAnimated(true, completion: nil)

You can do one thing.
As you are pushing your mywebViewController into the navigation controller, make the navigation bar visible.
By simply tapping on Back button in the navigation bar you can easily dismiss your mywebViewController.
Hope this helps you. :)

Add button in mywebViewController and in its #IBAction, call
self.dismissViewControllerAnimated(true, completion: nil)

Update for Swift 4 & 5
In the VC you're navigating from
navController.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.dismiss))
Have to declare your selector as an #objc func
#objc func dismiss(){
self.dismiss(animated: true)
}

Related

Change action of back bar button item

I want to be able to change the action of the back bar button item on a specific UIViewController in my navigation controller so that it pops to the root view controller. I've tried the following but they don't work:
let backButton = UIBarButtonItem(title: nil, style: .plain, target: self, action: #selector(back))
self.navigationItem.backBarButtonItem = backButton
and
self.navigationItem.backBarButtonItem?.action = #selector(back)
Any suggestions?
You should use self.navigationItem.leftBarButtonItem = backButton
Good luck
First of all backBarButtonItem action not works because you can only change back button title,take a look question about it here.
Solution
In ViewController from which you want to pop to root ViewController you need to set as a delegate of UINavigationControllerDelegate
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.delegate = self
}
and implement UINavigationControllerDelegate this method`
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
if viewController.isKind(of:PreviousViewController.self) {
navigationController.popToRootViewController(animated: animated)
}
}
If my answer not fit your needs you can check similar question here.
To keep the same look and feel of the back button but change the action, see the ViewWillDisappear answer to the question regarding, "Execute action when back bar button of UINavigationController is pressed" Execute action when back bar button of UINavigationController is pressed
This is your solution, just need to set target and selector, nothing more.
private func setNavBar() {
let item = navigationItem.backBarButtonItem
item?.target = self
item?.action = #selector(self.donePressed)
navigationItem.leftBarButtonItem = item
}
#objc private func donePressed() {
self.dismiss(animated: true, completion: nil)
}

Change back button place from left bar button to right Bar button with reverse animation

How can I change back button place to right bar button of embedded navigation and change the the icon from < to >?
My suggestion is:
Hide back button:
navigationItem.hidesBackButton = YES
Add a right button with an image arrow:
let backButton = UIBarButtonItem(title: ">", style: .Plain, target: self, action: #selector(backTapped))
navigationItem.rightBarButtonItem = backButton
the action of backTapped will pop the view controller from the navigation controller stack.
Let me know in the comments if this approach can resolve your problem.
I use :
let newView = sabtEnsheabViewController(nibName: "sabtEnsheabViewController", bundle: nil)
self.navigationController?.pushViewController(newView, animated: false)
but it show back button to another view
use this :
let newView = EnsheabSabteNamViewController(nibName: "EnsheabSabteNamViewController", bundle: nil)
self.presentViewController(newView, animated: false, completion: nil)
it doesn't show navigationBar anymore
I use this way for change back button position.
//put this code in viewDidLoad()
navigationItem.hidesBackButton = true
navigationItem.rightBarButtonItem = UIBarButtonItem(title: " > ", style: .done,target: self, action: #selector(addTapped))
//function to handle back navigation
#objc func addTapped(){
navigationController?.popToRootViewController(animated: true)
}

dismiss ViewC controller that i present it by using root

how could i dismiss a view controller that i call it by using this method
func openUpgradeAccount(){
let appdel = AppDelegate.sharedInstance()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let earnFreeSpace = storyboard.instantiateViewControllerWithIdentifier("IAPUpgradeVC") as! IAPUpgradeVC
let navigation:UINavigationController = UINavigationController(rootViewController: earnFreeSpace)
appdel.drawerController!.mainViewController = navigation
appdel.drawerController!.setDrawerState(.Closed, animated: true)
}
in this controller i add UIBarButtonItem to cancel id viewdidload method
let cancelBarBtn = UIBarButtonItem(title: NSLocalizedString("Cancel", tableName: appLocalizedTable, comment: ""), style: UIBarButtonItemStyle.Done, target: self, action: #selector(IAPUpgradeVC.didTapCancelButton(_:)))
cancelBarBtn.tintColor = UIColor.whiteColor()
self.navigationItem.leftBarButtonItem = cancelBarBtn
the didTapCancelButton method that i use to dismiss the view was
func didTapCancelButton(sender: UIBarButtonItem) {
self.dismissViewControllerAnimated(true) { () -> Void in
}
but when i tap cancel button nothing happen , what i want how can i return back to the last ViewController , can anyone help me ?
First of all, what is the drawerController? What's its superclass and what's its mainViewController supposed to be?
The method that you call when tapping the button is for dismissing a view controller presented modally. However before that, you do not present that view controller modally, setting is as drawerController's mainViewController instead:
appdel.drawerController!.mainViewController = navigation
One way to make it work is to change this line, so that instead of setting mainViewController you call presentViewController to present the new view controller modally.
If that is not how you want it to work (no presentation of view controllers), you'd have to elaborate on what you want both the new vc and the drawerController to do.

Dismissing a viewcontroller that is presented from UITabBarController in the app delegate

To achieve a similar effect to many photo apps I:
Set up my tab bar programmatically in the App delegate
Added a custom button on top of a tab bar item that I would like to use to launch the camera
(basically using this method: What's the best way of adding a custom centre button to a tab bar?)
Created a view controller that handles the camera functionality
I launch the view controller this way from the button and it works. However, I can't dismiss it effectively.
in didFinishLaunchingWithOptions :
var tabBC = UITabBarController()
//....
shutterButton.addTarget(self, action: "presentCamera:", forControlEvents: UIControlEvents.TouchUpInside)
tabBC.view.addSubview(shutterButton)
action attached:
func presentCamera(sender: AnyObject){
let composeSB = UIStoryboard(name: "Compose", bundle: nil) as UIStoryboard
let composeVC = composeSB.instantiateViewControllerWithIdentifier("composeVC") as ComposeViewController
self.window?.rootViewController!.presentViewController(composeVC, animated: false, completion: nil)
}
In ComposeViewController this method gets called but the view controller does not get dismissed. I would think this would dismiss the VC and I would see the views in the tabbarcontroller.
func cameraOverlayDidCancel() {
// I've tried:
dismissViewControllerAnimated(true, completion: nil)
//self.dismissViewControllerAnimated(true, completion: nil)
//self.view.parentViewController.dismissViewControllerAnimated(true, completion: nil)
}

How do i create a navigationBar in UITableViewController in Swift?

I am new to IOS,
I would like to add a UINavigationBar to UITableViewController, I have tried this:
var navBar: UINavigationBar = UINavigationBar(frame: CGRect(x:0, y:0, width:320, height:80))
then,
self.view .addSubview(navBar)
Thanks
You can not simplly add a NavigationBar to UITableViewController like that.
The simplest way to have UINavigationController and NavigationBar is to do it from Storyboard.
Steps:-
Drag the UITableViewController Object from Object Library to the Storyboard.
Highlight the UITableViewController, go to Edit -> Embed In -> Navigation Controller like the screen shot below:-
Go to File -> New -> File.. -> iOS -> Cocoa Touch Class, and create a Custom TableViewController class like below screen shot:-
Finally, go back to storyboard and highlight the UITableViewController object. Under the identity inspector, choose the custom class that you have just created like the screen shot below:-
You may do whatever you want with the custom class file. You may also add a custom UINavigationController class as well if you want and you may attach the custom class to to the object inside the storyboard.
If this is merely the case of showing a modal UITableViewController with a navigation bar, the easiest way to do this from code is to present a UINavigationController with your UITableViewController as the rootViewController:
Presenting view controller:
let sourceSelectorTableViewController = SourceSelectorTableViewController()
let navigationController = UINavigationController(rootViewController: sourceSelectorTableViewController)
self.presentViewController(navigationController, animated: true, completion: nil)
Destination modal UITableViewController:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "cancel")
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: "done")
self.title = "Pick a Source"
}
func cancel() {
self.dismissViewControllerAnimated(true, completion: nil)
}
func done() {
//save things
self.dismissViewControllerAnimated(true, completion: nil)
}
Well the best solution will be presenting the
UITableViewController
as
UINavigationController
let topicsList = TopicsListViewController()
let topicsListNavContrl = UINavigationController(rootViewController: topicsList)
presentViewController(topicsListNavContrl, animated: true) { () -> Void in
print("completed")
}
you can do that programmatically .
DataTableViewController *vc = [[DataTableViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];

Resources