Bar button item on every view with specific controller function - swift

I have to display a navigation bar button item on almost every view in the project.
I extended UIViewController
extension UIViewController{
func addNavBarItem(){
//add the bar button item
}
}
And I call addNavBarItem() on the viewDidLoad. However, the action taken when this button is tapped can be different for each view. Is there a way to set the target for this button to the actual view controller that called this method? Ideally I would want something like....
extension UIViewController{
func addNavBarItem(){
//do stuff
btn.addTarget(self, action: #selector(OriginalViewController.doSomething), forControlEvents: .TouchUpInside)
}
}
But OriginalViewController isn't available. Is there a quick solution or alternative pattern I should employ?

One solution that I use is to subclass UINavigationController and put my navigation bar item code in to the willShowViewController delegate method like so...
class MyNavigationController : UINavigationController {
override func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
super.navigationController(navigationController, willShowViewController: viewController, animated: animated)
let backButton = UIBarButtonItem(image: UIImage(named: "ic_menu"), style: UIBarButtonItemStyle.Plain, target: viewController, action: "doSomething")
viewController.navigationItem.leftBarButtonItem = backButton
}
}
This means when you add the target you can reference the exact viewController that is being shown by the navigation controller.

Related

How to pushViewController from a custom UIView in Swift?

I have a custom UIView and it will show when user go to specific UIViewController, on this UIView there is a button.
When user click on the button, I want to push a viewcontroller but I cannot call self.navigationController?.pushViewController(inputCode, animated: true)
How can I do the same behavior from a custom UIView? And also I am not using storyboard.
You can't access UIViewController from a custom UIView unless you pass its reference. Anyways, it wouldn't be nice if you do so. You can handle it by adding action from the UIViewController side
yourCustomView.yourActionButton.addTaget(self, action: #selector(self.tappedYourActionButton), forControlEvents: .touchUpInside)
#objc func tappedYourActionButton(_ sender: UIButton?) {
}

Navigation Controller inside Tab Bar Controller is showing but Right Bar Button not showing - Swift 4 - Programmatic Approach

I'm still new to iOS Dev.
Goal: Create an iOS App with Navigation Bar (with .add as right bar button) at the top and Tab Bar at the bottom screen using Programmatic approach (not using storyboards and xib)
So I did almost everything here: https://developer.apple.com/library/archive/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html
But apparently it doesn't work (maybe because it is old? idk) and I'm also not comfortable configuring the App Delegate yet.
So what I have are these:
CompanyViewController as UIViewController
AssessmentViewController as UIViewController
TabViewController as UITabBarController, UITabBarControllerDelegate
I tried putting navigation controllers inside each VCs (navigationBar when I tap Tab Bar Items, which is expected - but the Title and Right Bar Button is NOT showing
I tried creating Swift file UINavigationController and named it NavigationViewController then added it to the TabViewController -> viewControllers but what happened was it was added to the tab bars at the bottom of the screen so it's not what I need and it looks like an ordinary tab not a navigation bar.
This is the last one I tried which displays Navigation Controller with its title but not its right bar button...
class TabViewController: UITabBarController, UITabBarControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let tabOne = CompanyViewController()
let tabOneBarItem = UITabBarItem(title: "Company", image: .none, tag: 1)
tabOne.tabBarItem = tabOneBarItem
let tabTwo = AssessmentViewController()
let tabTwoBarItem2 = UITabBarItem(title: "Assessment", image: .none, tag: 2)
tabTwo.tabBarItem = tabTwoBarItem2
self.viewControllers = [tabOne, tabTwo]
setUpNavigation()
}
func setUpNavigation() {
navigationItem.title = "Company Assessmentz"
self.navigationController?.navigationBar.barTintColor = colorLiteral
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor:colorLiteral]
self.navigationController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(selectorX))
}
#objc func selectorX() { }}
replaced this:
self.navigationController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(selectorX))
to this:
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .camera, target: self, action: #selector(selectorX))

Force refresh on another ViewController component with swift

I'm trying to pass a trigger between 2 view controller but i can't find something that works ...
I have the main controller with a NSTableView, source linked, View Base.
main Controller class :
class ViewController: NSViewController {
I have an array defined in Global variables.
on the viewDidLoad i add 2 elements in my array, then i use setDelegate and setDataSource.
It works fine.
myLib.myCoins = fillCoinsTable()
print ("My lib has \(myLib.myCoins.count) objects ")
mainCoinTable.setDelegate(self)
mainCoinTable.setDataSource(self)
I have a segue from the WINDOWS CONTROLLER to my second view Controller.
(It's a ToolBar button). The segue is "Sheet" kind.
This second controller allows me to add an element in my global variable arrays, with a button "Save" .
Code on the second controller
#IBAction func addCoinButton(sender: AnyObject) {
//We add the coin
let newCoin:coin = coin(n: textName.stringValue)
newCoin.Year = Int.init(textYear.stringValue)
myLib.myCoins.append(newCoin)
self.dismissController(self)
}
If i add a button on the main controller, to reloadData on the TableView, it works fine. The third element is added.
but i would like that to be automatic ....
I tried segue, but mine is not between view controller but with the windows controller.
Can you please help ?
Thanks,
Nicolas
I think, you want to add data from oneViewController and without pressing button, you want after navigation or pressing back button, you want to reload automatically tableview to show updated results, right.
If I'm not wrong then, this solution will work for you.
Follow this below steps:
Step 1 :
Add this code in your view controller, from which you want to add data in array or in database, instead of button click.
override func viewDidLoad()
{
super.viewDidLoad()
let backItem = UIBarButtonItem(title: "Back", style: .Plain, target: self, action: "goBack")
self.navigationItem.leftBarButtonItem = backItem
}
func goBack()
{
NSNotificationCenter.defaultCenter().postNotificationName("load", object: nil)
self.navigationController?.popViewControllerAnimated(true)
}
Step 2:
Now its final step.
Now add this below code, to your result view controller, where you want to automatically update the result.
func loadList(notification: NSNotification){
self.TableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "loadList:",name:"load", object: nil)
}
Now implement this code-stuff in your coding. Hope it works for you.
If you want the table to reload automatically when the View appears add this to viewWillAppear
self.tableView.performSelectorOnMainThread(#selector(UITableView.reloadData), withObject: nil, waitUntilDone: true)

Swift - Overwrite navigation bar

When it comes to opening a new View Controller i didnt want it to be presented modally so i pushed it in navigation controller:
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("newView")
self.navigationController!.pushViewController(vc, animated: true)
The View with the identifier "newView" is presented correctly and there is also a navigation bar with a back-button provided, which also works properly.
But how to customize this existing navigation bar, add new bar button items etc.. ?
any suggestions?
Thanks and Greetings!
You are on the right track by subclassing from UIViewController the newView. I doubt you could customize the navigation bar on the storyboard.
You have to do it in code.
In viewDidLoad() of newView, you can have these:
var helloButton = UIBarButtonItem(title: "Hello", style: .Plain, target: self, action: "sayHello:")
self.navigationItem.rightBarButtonItem = helloButton
Implement the sayHello method:
func sayHello(sender: UIBarButtonItem) {
}

How to programmatically add a UITableViewController to a UINavigationViewController?

I have
class SortViewController: UINavigationController{
var myBtn: UIBarButtonItem?
var tvc = UITableViewController()
override func viewDidLoad() {
super.viewDidLoad()
myBtn = UIBarButtonItem(title:"Press Me", style: UIBarButtonItemStyle.Plain, target: self, action: "doStuff:")
tvc.navigationItem.leftBarButtonItem = sortBtn
self.pushViewController(tvc, animated: true)
tvc.tableView.reloadData()
}
with all the necessary override func tableView(...) functions below.
This is all in a popover view that is called by a different view. While the popover opens, and myBtn appears properly on the navigation bar on top of the table, the table does not populate as it should. - that is, it does not populate at all.
Any ideas why?
Note everything in my app is completely programmatic; no storyboard whatsoever - this is intentional.
Thanks in advance,
Jona
Assign delegate and dataSource property with self. Then only the methods of tableViewController will get called.