Search code examples
iosswiftuinavigationitemcustom-view

Custom UIView in NavigationController titleView. How can I have the buttons trigger actions in my View Controller


I have a custom uiview (call it navBarMenu) with five buttons as subviews. I added this navBarMenu to the navigationbar's titleView. The navBarMenu has its own class and nib file where the buttons are defined as iboutlets. How can I add targets so that when I click the button in the navBarMenu it will trigger a function in my viewcontroller that is embedded in the navigation controller? Using the method: navBarMenu.Button1.addTarget(self, action: "Button1Tapped:", forControlEvents: UIControlEvents.TouchUpInside) does not work and I get an error that it unexpectedly found nil while unwrapping an Optional value.

Edit: Here is the code for my view controller and my custom view.

class MyCustomView: UIView {

var view: UIView!
var nibName: String = "MyCustomView"

@IBOutlet weak var Button1: UIButton!
@IBOutlet weak var Button2: UIButton!
@IBOutlet weak var Button3: UIButton!
@IBOutlet weak var Button4: UIButton!
@IBOutlet weak var Button5: UIButton!

var Button1Text: String? {
    get {
        return Button1.titleLabel?.text
    }
    set(Button1Text) {
        Button1.setTitle(Button1Text, forState: UIControlState.Normal)
    }
}

var Button2Text: String? {
    get {
        return Button2.titleLabel?.text
    }
    set(Button2Text) {
        Button2.setTitle(Button2Text, forState: UIControlState.Normal)
    }
}

var Button3Text: String? {
    get {
        return Button3.titleLabel?.text
    }
    set(Button3Text) {
        Button3.setTitle(Button3Text, forState: UIControlState.Normal)
    }
}

var Button4Text: String? {
    get {
        return Button4.titleLabel?.text
    }
    set(Button4Text) {
        Button4.setTitle(ButtonText4, forState: UIControlState.Normal)
    }
}

var Button5Text: String? {
    get {
        return Button5.titleLabel?.text
    }
    set(Button5Text) {
        Button5.setTitle(ButtonText5, forState: UIControlState.Normal)
    }
}

override init(frame: CGRect) {
    super.init(frame: frame)

    setup()
    println("view is setup")
}
convenience init(controller: UIViewController) {

    var frameForNavBar: CGRect = CGRect(x: 0.0, y: 0.0, width: 548.0, height: 33.0)
    self.init(frame: frameForNavBar)


    Button1.addTarget(controller, action: "Button1Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
    Button2.addTarget(controller, action: "Button2Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
    Button3.addTarget(controller, action: "Button3Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
    Button4.addTarget(controller, action: "Button4Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
    Button5.addTarget(controller, action: "Button5Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

func setup() {
    view = loadViewFromNib()
    view.frame = bounds
    addSubview(view)
}

func loadViewFromNib() -> UIView {
    let bundle = NSBundle(forClass: self.dynamicType)
    let nib = UINib(nibName: nibName, bundle: bundle)
    let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

    return view
}

}

class MyViewController: UIViewController, UINavigationBarDelegate {

@IBOutlet weak var webView: UIWebView!

func Button1Tapped(sender: AnyObject) {
    println(__FUNCTION__)
}
func Button2Tapped(sender: AnyObject) {
    println(__FUNCTION__)
}
func Button3Tapped(sender: AnyObject) {
    println(__FUNCTION__)
}
func Button4Tapped(sender: AnyObject) {
    println(__FUNCTION__)
}
func Button5Tapped(sender: AnyObject) {
    println(__FUNCTION__)
}

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {

    super.init(nibName: "MyViewController", bundle: nil)

}
convenience init() {
    self.init(nibName: "MyViewController", bundle: nil)
    tabBarItem.title = "MyVC"
    tabBarItem.image = UIImage(named: "MyImage")
}
required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
    super.viewDidLoad()

    let navBarMenu = MyCustomView(controller: self)
    positionForBar(navigationController!.navigationBar)
    self.navigationItem.titleView = navBarMenu
    self.navigationController?.navigationBar.translucent = false
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func loadWebPage() {

}

func positionForBar(bar: UIBarPositioning) -> UIBarPosition {
    return UIBarPosition.TopAttached
}

}


Solution

  • When you initialize your customView you can pass the UIViewController parameter and then add target for your button to it.

    let myCustomView = MyCustomViewClass(self)
    

    And in your MyCustomViewClass you can use:

    init (controller: UIViewController) {
        // use controller, not self
        button.addTarget(controller, action: "Button1Tapped:", forControlEvents: UIControlEvents.TouchUpInside)
    }