common Navigation Button Action another class - ios

I have made common Navigation bar For all View Controllers. But I need to button action on that which calls I am calling the common navigation bar
#objc extension UIViewController {
#objc func setBarButtonItem(titleLabel: String)
{
let view = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 200 + 4, height: 38))
let Nextbtn = UIButton(type: .custom)
Nextbtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
Nextbtn.addTarget(self, action: #selector(NextButtonClicked), for: .touchUpInside)
view.addSubview(Nextbtn)
self.navigationItem.setLeftBarButton(UIBarButtonItem(customView: view), animated: true)
/*
#objc func NextButtonClicked()
{
}*/
}
}
Calling Controller---> setBackBarButton("hello...")
Button is called if I made button action method on this class. But I want to make button action method func NextButtonClicked() on this calling Calling Controller class,Or Any approach we can access the button action on this class.
#objc func NextButtonClicked()
{
}

You can just Create BaseViewController Instead extension and allow all ViewControllers to inherit From this BaseViewController
BaseViewController:
import UIKit
class BaseViewController: UIViewController {
typealias CompletionBarButtonClicked = (()-> Void)
var completionBarItemClicked:CompletionBarButtonClicked?
override func viewDidLoad() {
super.viewDidLoad()
}
#objc func setBarButtonItem(titleLabel: String, completion :#escaping CompletionBarButtonClicked)
{
self.completionBarItemClicked = completion
let view = UIView.init(frame: CGRect.init(x: 0, y: 0, width: 200 + 4, height: 38))
let Nextbtn = UIButton(type: .custom)
Nextbtn.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
Nextbtn.addTarget(self, action: #selector(NextButtonClicked), for: .touchUpInside)
view.addSubview(Nextbtn)
self.navigationItem.setLeftBarButton(UIBarButtonItem(customView: view), animated: true)
}
#objc func NextButtonClicked()
{
if let completionHandler = completionBarItemClicked{
completionHandler()
}
}
}
Example ViewController:
import UIKit
class ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.setBarButtonItem(titleLabel: "test") {
/// your action There
}
}
}

Related

Why is my button not working in Swift Playgrounds?

I am trying to make a playground and I have a button that says "Let's play!" and moves into a new view controller.
I looked at the code from this website and put it into my code:
http://lab.dejaworks.com/ios-swift-3-playground-uibutton-action/
This is all of my code (like, all of it):
import UIKit
import PlaygroundSupport
class MyViewController : UIViewController {
override func loadView() {
//Introduction
let view = UIView()
view.backgroundColor = .red
//title
func labelCool() {
let label = UILabel()
label.frame = CGRect(x: 50, y: 300, width: 400, height: 100)
label.text = "Add-Add - A Wonderful Game!"
//label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.numberOfLines = 3
label.font = UIFont(name: "HelveticaNeue-Bold", size: 30)
UILabel.animate (withDuration: 10.0, animations:{
label.textColor = .black
})
UILabel.animate(withDuration: 5.0, animations:{
label.textColor = .blue
})
view.addSubview(label)
}
labelCool()
//subtitle
let subtitle = UILabel()
subtitle.frame = CGRect(x: 50, y: 400, width: 200, height: 50)
subtitle.text = "Curated and Created by Yours Truly, Adit Dayal!"
subtitle.numberOfLines = 4
self.view = view
view.addSubview(subtitle)
}
override func viewDidLoad() {
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
let responder = Responder()
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
view.addSubview(button)
}
}
class gameViewController: UIViewController {
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
For now, I just want the button to display "Yay!" when clicked, but it is doing nothing!
Does anyone know why? (I'm on a bit of a time constraint)
Thank you so much,
Adit Dayal
Your Responder class is inside the viewDidLoad() function put the class outside like so
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
override func viewDidLoad() {
let responder = Responder()
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(responder.action), for: .touchUpInside)
view.addSubview(button)
}
The problem is that you are creating the responder object inside the viewDidLoad, as a local variable; this cause the object to be destroyed when the function ends (but we want that object alive even after). You have to retain that object, so instead of creating a local variable, create an instance variable by simply saving it as a class scope:
class Responder : NSObject {
#objc func action() {
print("Yay!")
}
}
let responder = Responder() // this is now outside the viewDidLoad, so it's an instance variable
override func viewDidLoad() {
//next page
let button = UIButton(frame : CGRect(x: 0, y: 500, width: 200, height: 50))
button.setTitle("Let's Play!", for: .normal)
button.backgroundColor = .blue
button.addTarget(responder, action: #selector(Responder.action), for: .touchUpInside)
view.addSubview(button)
}

Swift Playground in Xcode - TapGestureRecognizer to UILabel not working

I am creating a Swift Playground in Xcode and I have a problem with putting a TapGestureRecognizer to an UILabel...
class MyViewController : UIViewController {
override func loadView() {
func tapped() {
print("The label was tapped!")
}
let label11 = UILabel()
label11.frame = CGRect(x: -350, y: 360, width: 350, height: 20)
label11.text = "name."
label11.textColor = .black
label11.isUserInteractionEnabled = true
view.addSubview(label11)
let tap = UITapGestureRecognizer(target: self, action: "tapped")
label11.addGestureRecognizer(tap)
}
}
It appears that you're creating the view controller programmatically since you're operating solely in loadView (where you correctly did not call super), which requires you to create the actual view of that controller.
import UIKit
import PlaygroundSupport
class MyViewController: UIViewController {
override func loadView() {
view = UIView()
let label11 = UILabel()
label11.frame = CGRect(x: 0, y: 360, width: 350, height: 20)
label11.text = "name."
label11.textColor = .yellow
label11.isUserInteractionEnabled = true
view.addSubview(label11)
let tap = UITapGestureRecognizer(target: self, action: #selector(tapped))
label11.addGestureRecognizer(tap)
}
#objc func tapped() {
print("The label was tapped!")
}
}
PlaygroundPage.current.liveView = MyViewController()
Alternatively, you can replicate a non-programmatic view controller by using viewDidLoad (which requires you to call super).
import UIKit
import PlaygroundSupport
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let label11 = UILabel()
label11.frame = CGRect(x: 0, y: 360, width: 350, height: 20)
label11.text = "name."
label11.textColor = .yellow
label11.isUserInteractionEnabled = true
view.addSubview(label11)
let tap = UITapGestureRecognizer(target: self, action: #selector(tapped))
label11.addGestureRecognizer(tap)
}
#objc func tapped() {
print("The label was tapped!")
}
}
PlaygroundPage.current.liveView = MyViewController()
Also, your origin-x value was out of bounds which is why you may not have seen the label and you were missing #objc syntax which is required in Swift 4.

How can I get events to my (sub) UIView?

I'm new to Swift and have a hard time understand the event flow. The code below can be run directly in an xcode playground. I have a white UIView in the background. This view has a brown button and a red view as sub-views. Click on them and the events are logged in the controller, just as expected.
But the controller of this white view also adds another view, that has it's own controller class (SubviewController). SubviewController is green and has a blue subview with a black button. Question is... why don't I get any logs from the green, blue and black views/buttons?
import Foundation
import UIKit
import PlaygroundSupport
class TestViewController : UIViewController {
let playButton: UIButton = {
let playButton = UIButton(frame: CGRect(x: 155, y: 135, width: 160, height: 40))
playButton.setTitle("BROWN BUTTON", for: .normal)
playButton.backgroundColor = UIColor.brown
return playButton
}()
override func loadView() {
let viewWhite = UIView()
viewWhite.backgroundColor = UIColor.white
let viewRed = UIView()
viewRed.backgroundColor = UIColor.red
viewRed.frame = CGRect(x: 20, y: 20, width: 40, height: 10)
viewRed.clipsToBounds = true
let recognizer2 = UITapGestureRecognizer(target: self, action: #selector (self.handleTapRed(_:)))
viewRed.addGestureRecognizer(recognizer2)
let recognizer = UITapGestureRecognizer(target: self, action: #selector (self.handleTap(_:)))
viewWhite.addGestureRecognizer(recognizer)
playButton.addTarget(self, action: #selector (self.action) , for: .touchUpInside)
let catList = SubviewController()
viewWhite.addSubview(catList.view)
viewWhite.addSubview(playButton)
viewWhite.addSubview(viewRed)
self.view = viewWhite
}
func action() {
print("Brown button tapped")
}
func handleTap(_ sender:UITapGestureRecognizer){
print("WHITE VIEW (background view) TAPPED")
}
func handleTapRed(_ sender:UITapGestureRecognizer){
print("RED VIEW TAPPED")
}
}
class SubviewController: UIViewController {
let buttonBlack: UIButton = {
let button = UIButton(frame: CGRect(x: 40, y: 10, width: 170, height: 20))
button.backgroundColor = UIColor.black
button.setTitle("BLACK BUTTON", for: .normal)
return button
}()
let viewBlue: UIView = {
let v = UIView()
v.backgroundColor = UIColor.blue
v.frame = CGRect(x: 20, y: 40, width: 240, height: 60)
v.clipsToBounds = true
return v
}()
override func loadView() {
super.loadView()
self.view.backgroundColor = UIColor.green
buttonBlack.addTarget(self, action: #selector (self.blackKlick) , for: .touchUpInside)
self.view.addSubview(viewBlue)
self.view.frame = CGRect(x: 0, y: 40, width: 240, height: 60)
self.view.clipsToBounds = true
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapGreen(_:))))
viewBlue.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector (self.handleTapBlue(_:))))
viewBlue.addSubview(buttonBlack)
}
func blackKlick() {
print("Black button tapped")
}
func handleTapBlue(_ sender:UITapGestureRecognizer){
print("BLUE VIEW TAPPED")
}
func handleTapGreen(_ sender:UITapGestureRecognizer){
print("GREEN VIEW TAPPED")
}
}
PlaygroundPage.current.liveView = TestViewController()
Thanks for any help!
This line in your current code:
let catList = SubviewController()
creates a local instance of SubvieController. As soon as you exit the loadView() func, that instance is gone.
So, you need a class-level variable to keep that instance around. Add this line:
class TestViewController : UIViewController {
var catList: SubviewController!
and then remove the let from the instantiation line in loadView():
catList = SubviewController()

Swift: Calling UIButton press from another class

I have my ViewController.class and a Menu.class
In the Menu.class I create and setup all the buttons and in the ViewController.class I add the Menu to the view. When I run the code everything is shown on the screen but I am not able to press the button.
This is how my ViewController looks like:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let menu = Menu()
menu.setupView(controller: self, width: 600, height: 120)
self.view.addSubview(menu)
// Do any additional setup after loading the view, typically from a nib.
}
}
And this is my Menu:
import Foundation
import UIKit
class Menu: UIView{
func setupView(controller: ViewController, width: CGFloat, height: CGFloat){
let newGame = UIButton(frame: CGRect(x: controller.view.center.x, y: 300, width: width, height: height))
newGame.center = CGPoint(x: controller.view.center.x, y: 300)
newGame.setTitle("New Game", for: .normal)
newGame.backgroundColor = UIColor.gray
newGame.titleLabel?.font = UIFont(name: "Helvetica", size: 42)
newGame.setTitleColor(UIColor.black, for: .normal)
newGame.addTarget(self, action: #selector(Menu.newGame), for: .touchUpInside)
self.addSubview(newGame)
}
func newGame(){
print("New Game")
}
}
What is my mistake. Do I need to do more initializing so it is able to detect a press?
This is how you should do it. Repeat the operation for buttonTwo and label. Setup the view in viewDidLoad() and setup the frames in viewDidLayoutSubviews.
If you subclass any UIView you should setup the frames in layoutSubviews()
If you want to display a tableView when you click on newGame then create a new UIViewController. Add a UITableView in it, the same way you did add Button and Label in ViewController
import UIKit
class ViewController: UIViewController {
let buttonOne = UIButton()
let buttonTwo = UIButton()
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
buttonOne.backgroundColor = UIColor.gray
buttonOne.setTitle("New Game", for: .normal)
buttonOne.titleLabel?.font = UIFont(name: "Helvetica", size: 42)
buttonOne.setTitleColor(UIColor.black, for: .normal)
buttonOne.addTarget(self, action: #selector(newGame), for: .touchUpInside)
view.addSubview(buttonOne)
view.addSubview(buttonTwo)
view.addSubview(label)
}
override func viewDidLayoutSubviews() {
buttonOne.frame = CGRect(x: 0, y: 300, width: 600, height: 120)
buttonOne.center.x = self.view.center.x
}
func newGame(sender: UIButton?) {
print("New Game")
}
}

How can I change the properties of a UIViewController based on the action that switched to it?

In the app I'm writing, I have to show a lot of different pages with different text; I'd rather not use a lot of different views that are basically identical in structure.
My idea is that I have a single view for displaying text-only content, and programatically change the title (that shows in the nav bar) and the content based on the button that was pressed to open the view.
I can link the UITextView to a variable via #IBOutlet but I'm not sure how I can reference the view that's being loaded to change this.
How about creating two properties for content and title in your destination controller and populate the values based on button click. Here is simple demo of this requirement.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib
self.addButtons()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Add Buttons
func addButtons() {
var button1 = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button1.setTitle("Content 1", forState: UIControlState.Normal)
button1.backgroundColor = UIColor.redColor()
button1.tag = 1
button1.addTarget(self, action : "showContent:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button1)
var button2 = UIButton(frame: CGRect(x: 100, y: 200, width: 100, height: 50))
button2.setTitle("Content 2", forState: UIControlState.Normal)
button2.backgroundColor = UIColor.blueColor()
button2.tag = 2
button2.addTarget(self, action : "showContent:", forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button2)
}
func showContent(sender: UIButton!) {
var displayContentController = DisplayContentController()
switch (sender.tag) {
case 1:
displayContentController.content = "Test Content 1"
displayContentController.titleText = "Content1"
break;
case 2:
displayContentController.content = "Test Content 2"
displayContentController.titleText = "Content2"
break;
default:
break;
}
self.presentViewController(displayContentController, animated: true,completion: nil)
}
}
class DisplayContentController: UIViewController {
var contentView:UITextView?
var titleLabel:UILabel?
var content: String?
var titleText: String?
override func viewDidLoad() {
super.viewDidLoad()
self.addTextView()
self.addTitleLabel()
titleLabel?.text = titleText
contentView?.text = content
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK:- Add UILabel
func addTitleLabel() {
titleLabel = UILabel(frame: CGRect(x: 100, y: 5, width: 100, height: 50))
titleLabel?.textColor = UIColor.whiteColor()
self.view.addSubview(titleLabel!)
}
//MARK:- Add UITextView
func addTextView() {
contentView = UITextView(frame: CGRect(x: 5, y: 60, width: 250, height: 250))
self.view.addSubview(contentView!)
}
}
If you are using segues in storyboard, you can cast segue's destinationController as the type of view controller that you have and pass information to it.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let someViewController = segue.destinationViewController as SomeViewController
someViewController.someProperty = someValue
}

Resources