NavigationController doesn't see right bar button item - swift

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

Related

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)

How to make actionsheet pop over a bar button on iPhone

I know how to make an action sheet pop over a button on iPad but not for iPhone. it seems that on iphone the action sheet doesn't have popoverPresentationController:
#IBAction func addChannel(_ sender: Any) {
let sender = sender as? UIBarButtonItem
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let addChanel = UIAlertAction(title: "Add a Channel", style: .default) { (_) in
self.addChannel()
}
let addContact = UIAlertAction(title: "Add a Contact", style: .default){ _ in
self.addContact()
}
actionSheet.addAction(addChanel)
actionSheet.addAction(addContact)
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel))
// actionSheet.popoverPresentationControlle
if let popover = actionSheet.popoverPresentationController{
actionSheet.popoverPresentationController?.barButtonItem = sender
actionSheet.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.down
}
self.present(actionSheet, animated: true)
}
I want the action sheet pop over a button just like what WeChat + button does. Other stackoverflow answers are too old and not workable
Any idea is welcome!
Source.
You cannot use UIAlertController as a popover on iPhones. One of alternatives is using a UITableView or something inside new UIViewController, which you can create like described below (Swift 5.0).
import UIKit
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet private weak var button: UIButton!
#IBAction func buttonAction() {
let vc = UIViewController()
vc.view.backgroundColor = UIColor.blue
vc.preferredContentSize = CGSize(width: 200, height: 200)
vc.modalPresentationStyle = .popover
let ppc = vc.popoverPresentationController
ppc?.permittedArrowDirections = .any
ppc?.delegate = self
ppc?.sourceView = button
present(vc, animated: true, completion: nil)
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Also, popoverPresentationController has property called barButtonItem which you can assign to your nav bar button.

UINavigation controller: present and dismiss programmatically

I have a TableViewController which I want to present modally and I need it to have a NavigationBar.
To get that navbar, I have an embedded UINavigationController and as far as I know, that UINavigationController is what I have to present modally, so that's what I've done.
Everything works just fine, but I can't manage to dismiss that controller properly. Here is what I've got so far:
func presentErrorMessages(errorMessages: [String]) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Message", bundle: nil)
let infoMessagesNavigationViewController = storyBoard.instantiateViewController(withIdentifier: "InfoMessagesNavigation") as! ModalNavigationController
let infoMessagesTableViewController = infoMessagesNavigationViewController.viewControllers[0] as! InfoMessagesTableViewController
infoMessagesTableViewController.errorMessages = errorMessages
self.navigationController?.present(infoMessagesNavigationViewController, animated: true)
}
I use that to present ModalNavigationController, and this to dismiss it:
class ModalNavigationController: BaseNavigationController {
var backNavItem = UINavigationItem()
var okNavItem = UINavigationItem()
override func viewDidLoad() {
super.viewDidLoad()
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(dismissModal))
backNavItem.leftBarButtonItem = backButton
...
var items = [UINavigationItem]()
items.append(backNavItem)
self.navigationBar.items = items
}
#objc func dismissModal() {
self.dismiss(animated: true)
}
}
When I press that back button, there is no change but the navbar which gets blank (with no title). I have the feeling that the application just 'forgets' what is the NavigationController used before the new one is presented.
How can I solve this?
Try something like this:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .done, target: self, action: #selector(dismissModal))
...
}
#objc func dismissModal() {
self.dismiss(animated: true, completion: nil)
}
I managed to solve the problem by placing and invoking the dismissfunction on my TableViewController rather than my NavigationController:
...
public func setBackButton(){
if self.navigationController != nil {
let item = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(dismissModal))
self.navigationItem.leftBarButtonItem = item
}
}
#objc func dismissModal() {
self.dismiss(animated: true)
}

UIPopoverPresentationController popover displays over the entire view

I am trying to create a rightBarButtonItem that appears throughout my app. When this barItem is clicked I want to show a modal popup using UIPopoverPresentationController. I have been able to get the button to show up on the barItem on all the views. However when i click on the button the xib takes over the entire view (including nav bar, see image below). Please see the class below:
class MyAppsNavigationController: UINavigationController, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.navigationBar.barTintColor = Colors.Red01.color()
self.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "Ellipsis"), style: .plain, target: self, action: #selector(displayMenu(sender:)))
}
func displayMenu(sender: UIBarButtonItem)
{
let filterVC = DropdownMenuController(nibName: "DropdownMenuController", bundle: nil)
let nav = UINavigationController(rootViewController: filterVC)
nav.modalPresentationStyle = UIModalPresentationStyle.popover
//nav.isNavigationBarHidden = true
nav.preferredContentSize = CGSize(width: 200, height: 300)
let popover = nav.popoverPresentationController! as UIPopoverPresentationController
popover.permittedArrowDirections = .up
popover.delegate = self
popover.barButtonItem = self.navigationItem.rightBarButtonItem
popover.sourceView = self.view;
var frame:CGRect = (sender.value(forKey: "view")! as AnyObject).frame
frame.origin.y = frame.origin.y+20
popover.sourceRect = frame
popover.delegate = self
self.present(nav, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Result when clicked on the button:
When clicked the popup takes over entire view:
Any chance you're not using the right delegate method? I think this looks better:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Also, in this case sourceView and sourceRect is not needed: specifying a barButtonItem for the popover presentation controller is sufficient.
https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller/1622314-barbuttonitem

How change action BackButton in UISplitViewController?

I have Split View Controller.
I want change action back buttun on swift.
What me do?
Try this:
override func viewDidLoad() {
super.viewDidLoad()
var button = UIBarButtonItem(title: "YourNewButton", style: UIBarButtonItemStyle.Bordered, target: self, action: "doSomething")
self.navigationItem.leftBarButtonItem = button
}
func doSomething()
{
//do something
var vc = YourDestinationViewController()
self.presentViewController(vc, animated: true, completion: nil)
}