NavigationBar Right Items Hides when Show inner ViewControllers - swift

I use navigation bar with tabbarcontroller. When i push one of my tabs my navigationbar right items are hiding automatically.
How i can move my items to childs controllers?

You can create base view controller and inherit your children classes from base view controller then call super.viewDidLoad()
1- Base controller
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myButton = UIBarButtonItem(title: "LogOut", style: .done, target: self, action: #selector(self.logoutTapped(_:)))
self.navigationItem.rightBarButtonItem = myButton
}
#objc func logoutTapped(_ sender: UIBarButtonItem) {
print("Logout clicked :) ")
}
}
2- VC one
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
3- VC two
class ViewController2: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
Result

Related

Button title set only for the second tab

In my project there is a Segue Show(e.g. Push). After clicking the mainButton, TabBarController is presented. When I choose the second tab, the method setButtonsTitle is called and when I swipe the TabBarController down, I can see "item 2" instead of the "Button" title (default title). But when I click the first tab afterwards and swipe the TabBarController down, it remains "Button". My first thought was that the method does not get called, but this is not true (checked in debugger). Also, print(title) shows "Item 1".
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var mainButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destination = segue.destination as! TabBarController
destination.selectionDelegate = self
}
}
extension ViewController : ButtonThings {
func setButtonsTitle(title: String){
mainButton.titleLabel?.text = title
print(title)
}
}
And the TabBarController:
import UIKit
class TabBarController: UITabBarController {
weak var selectionDelegate: ButtonThings?
override func viewDidLoad() {
super.viewDidLoad()
}
//MARK: UITabBarController
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
selectionDelegate?.setButtonsTitle(title: item.title ?? "no title")
}
}
protocol ButtonThings : class {
func setButtonsTitle(title: String)
}
I was able to reproduce that issue that you had mentioned. I then set the button type to custom and the button title started showing correctly.
Hope this helps.

Setting title of UINavigationbar not working

I've looked through a few online tutorials, but nothing is working.
That's the code of my viewController:
import UIKit
class ViewController: UINavigationController {
let textView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// tried this
self.navigationItem.title = "AAA"
// and this
self.title = "AAA"
// and finally this
self.parent?.title = "AAA"
}
}
I don't understand why this isn't working (I haven't used a navigation bar before)
I didn't change anything in the main.storyboard.
Thanks for your answers.
First of all in your storyboard select your view controller and then
Editor -> Embed In -> Navigation Controller
then in your ViewController class add
self.title = "AAA"
in your viewDidLoad method and your code will look like:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "AAA"
}
}
You need to replace UINavigationController with UIViewController
Select ViewController from the storyboard.
Go to the Editor and Embed with Navigation Controller
1) Select Navigation Item and set title from the storyboard.
2) By Programmatically
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Your Title"
}
}

UIViewControllers sharing 'generic' IBAction

I have an app with 6 UIViewControllers.
ANY viewcontroller features a function like this one:
#IBAction func onHelp(_ sender: UIBarButtonItem) {
DispatchQueue.main.async(execute: { () -> Void in
let helpVC = self.storyboard?.instantiateViewController(withIdentifier: "Help") as! HelpViewController
helpVC.starter = "MapHelp"
helpVC.helpSubtitle = "Map"
self.present(helpVC, animated: true, completion: nil)
})
}
Any IBAction in any viewcontroller presents the same HelpViewController but passing different parameters (starter and helpSubtitle).
Since I don't like to repeat code, first of all I thought this function should be converted to something more generic.
But: is there any way to create a generic IBAction, working for every viewcontroller?
Create a BaseViewController and add the generic method there.
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func genericMethod(starter: String, helpSubtitle: String){
let helpVC = self.storyboard?.instantiateViewController(withIdentifier: "Help") as! HelpViewController
helpVC.starter = starter
helpVC.helpSubtitle = helpSubtitle
self.present(helpVC, animated: true, completion: nil)
}
#IBAction func onHelp(_ sender: UIButton?) {
//You can use this method as generic IBaction if you want. It can be connected to buttons of all child View Controllers. But doing so will limit your param sending ability. On the plus side though, you won't have to define an IBAction everywhere and you can simply connect your child VC's button to Parent Class' IBAction.
}
}
Now inherit your ViewControllers from this class like:
import UIKit
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func btnTapped(_ sender: Any) {
genericMethod(starter: "View Controller", helpSubtitle: "I was triggered from VC1")
}
}
and
import UIKit
class SecondViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func btnTapped(_ sender: Any) {
genericMethod(starter: "View Controller 2", helpSubtitle: "I was triggered from VC2")
}
}
That's it. Both your ViewControllers can call the parent method. If you still want to use the generic IBAction, you can do that too but I'd not recommend that course given that you want to pass params that can vary. If you wanted to do it though, it would look like this:
Bear in mind, the ViewController here has been inherited from the base ViewController which is why it can access the IBActions defined in the parent class. All you have to do is drag and connect.

Changing NavigationItem title

I'm trying to change the title in Product but somehow the navigationItem is different. How come the navigationItem in Container is different compared to the one in Product?
class VC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let controller = Container()
let navigation = UINavigationController(rootViewController: controller)
navigationController?.pushViewController(navigation, animated: true)
}
}
class Container: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(navigationItem)
navigationItem.title = "test"
let controller = Product()
controller.didMove(toParentViewController: self)
self.addChildViewController(controller)
view.addSubview(controller.view)
}
}
class Product: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print(navigationItem)
navigationItem.title = "" // Doesn't remove the title
}
}
I'm just reading the documentation for navigationItem, and it says this:
This is a unique instance of UINavigationItem created to represent the view controller when it is pushed onto a navigation controller.
However, in your case, the embedded VC is not a direct child of a navigation controller.
So, I tried the following code and it worked. The key part is I overrode navigationItem to return the parent's navigation item if there is a parent view controller.
override var navigationItem: UINavigationItem {
if let parentItem = parent?.navigationItem {
return parentItem
} else {
return super.navigationItem
}
}

Popovers in Storyboard, how to handle the delegate

In a storyboard i have a view controller which has a segue to another viewcontroller, with the "Present As Popover" applied. If i don't add any code, this works as id expect.
Issue:
I need to get the delegate working so i can get data back from the popover. I have created the delegate in the popover.
I have added
class LoginView: UIViewController,UIPopoverPresentationControllerDelegate, UIPopoverControllerDelegate,KeypadDelegate
I have added the functions to my main view controller.
Issue i have is how to set the delegate on the segue.
i have tried
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "KeyPadLoad"
{
let popoverViewController = segue.destinationViewController as! UIViewController
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
popoverViewController.popoverPresentationController!.delegate = self
}
}
The segue is defiantly called KeyPadLoad but when the delegate functions should be called in the popover nothing happens.
What am i doing wrong
Thanks
You have to implement the UIPopoverPresentationControllerDelegate in the class that presents the Popover. The methods of the UIPopoverPresentationControllerDelegate protocol let you customize the behavior of a popover-based presentation.
If you have set a segue to go to the Popover and you set the segue as Present as Popover then your class has to be like this :
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var popOver = segue.destinationViewController as! PopOverViewController
popOver.popoverPresentationController!.delegate = self
}
// Tells the delegate that the popover was dismissed.
func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
println("dismissed")
}
}
Where the class PopOverViewController is just an UIViewController that handle the Popover, no more, something like this code :
class PopOverViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
With the above code you should see the message:
dismissed
Every time that the PopOverViewController is dismissed.
I hope this help you.