Cannot attach existing method to UIButton - swift

I'm attempting to make a mock-up application, but I cannot seem to get the UIButton to hook up to the action that should be executed when I click it.
I'm not sure why it cannot find the method, the names are the same and adding in a (_:) to the #selector does nothing.
import UIKit
class LoginViewController: UIViewController {
var loginButton: UIButton?
#objc func onLoginButtonPress(sender: UIButton!) {
print("Login Button Press")
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setup()
}
func setup() -> Void {
initLoginButton()
self.view.backgroundColor = .green
}
func initLoginButton() -> Void {
let loginButtonBounds = CGRect(x: 100, y: 100, width: 250, height: 250)
loginButton = UIButton(frame: loginButtonBounds)
loginButton!.backgroundColor = .red
loginButton!.setTitle("Login", for: .normal)
loginButton!.addTarget(self, action: #selector("onLoginButtonPress"), for: .touchUpInside)
self.view.addSubview(loginButton!)
}

loginButton!.addTarget(self, action: #selector(onLoginButtonPress(sender:)), for: .touchUpInside)
edit this line code, this should work for you. Its better to not use force-unwrapping so avoid using it.

Have you tried removing the parenthesis from "onLoginButtonPress"? I don't think they are needed.
loginButton!.addTarget(self, action: #selector("onLoginButtonPress"), for: .touchUpInside)

Related

How do I targeting selector with addTarget in another class

I try to understand how to control component form one class to another class but that's not working.
class VC:UIViewController {
override func viewDidLoad() {
let instance = Test()
self.view.addSubView(instance.button)
}
}
class Test:NSObject {
var button:UIButton!
override init() {
button = UIButton(frame:CGRect(x:0, y:0, width:100, height:40))
button.setTitle(("TEST", for:.normal)
button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
}
#objc func tapButton(_ sender:UIButton) {
print("TAP Button")
}
}
When I tapped the button, nothing happens !
I try to change
button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
with
button.addTarget(nil, action: #selector(tapButton(_:)), for: .touchUpInside)
That's not working !
How to resolve this problem ?
Thanks for your help.
You have 3 issues:
instance is a local variable, so it gets deallocated as soon as viewDidLoad() finishes. Make it a property of VC. The button only keeps a weak reference to the object, so when it is deallocated it becomes nil. In cases where the target is nil, UIKit will search up the responder chain for the action method. Since VC doesn't supply a tapButton method, nothing happens when the button is pressed.
You need to call super.init() so that self is available to be used with the button. self can't be created until all properties have been initialized. Because init is an override, you must call super.init() to initialize the properties that NSObject provides before you can use self in the button.
Your frame puts your button in an unaccessible region of the screen. I changed your frame to put the button inside the safe area of the iPhone 11. I also made the button .green so that I could see it.
class VC: UIViewController {
var instance = Test() // make instance a property
override func viewDidLoad() {
// let instance = Test() // this was a local variable that doesn't hang around
self.view.addSubview(instance.button)
}
}
class Test: NSObject {
var button: UIButton!
override init() {
super.init() // call this so that you can use self below
button = UIButton(frame:CGRect(x: 100, y: 100, width: 100, height: 40))
button.setTitle("TEST", for:.normal)
button.backgroundColor = .green
button.addTarget(self, action: #selector(tapButton(_:)), for: .touchUpInside)
}
#objc func tapButton(_ sender: UIButton) {
print("TAP Button")
}
// Add deinit to see when this object is deinitialized. When
// instance is local to viewDidLoad() this object gets freed
// when viewDidLoad() finishes.
deinit {
print("Oops, the Test object has been deinitialized")
}
}

Creating a checkbox programmatically using images as the UIButtons background

I have seen multiple questions on how to implement a checkbox by just changing the background image when clicked, but I don't understand why the checkbox only shows when I add it to my ViewController setupViews.
It simply will not show up or change when I have all the functionality in my actionButton function. Should i be using a protocol and delegate set up to get my button showing changing when clicked? Below is my code, I am hoping someone can shed some light as to what I am missing here?
class MainMenuViewController: UIViewController {
let clickingCheckbox = ClickingCheckbox()
var checkbox = UIImage(named: "Checked_Checkbox")
var empty_checkbox = UIImage(named:"Empty_Checkbox")
var isBoxClicked: Bool!
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
self.backgroundImage.addSubview(contentView)
self.contentView.addSubview(clickingCheckbox)
clickingCheckbox.snp.makeConstraints { (make) in
make.top.equalTo(signInButton.snp.bottom).offset(-MainMenuViewController.padding)
make.leading.equalTo(buttonView)
make.width.equalTo(signInButton).multipliedBy(0.2)
make.height.equalTo(clickingCheckbox.snp.width)
}
clickingCheckbox.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
clickingCheckbox.setImage(empty_checkbox, for: UIControlState.normal) #The checkbox only shows on screen if I put it here, however it does nothing when clicked!
}
#objc func buttonAction(_ sender: ClickingCheckbox) {
if isBoxClicked == true {
isBoxClicked = false
}else{
isBoxClicked = true
}
if isBoxClicked == true {
sender.setImage(checkbox, for: UIControlState.selected)
}else{
sender.setImage(empty_checkbox, for: UIControlState.normal)
}
print("test")
}
In my Class I have.....
class ClickingCheckbox: UIButton {
override func draw(_ rect: CGRect) {
super.draw(rect)
}
}
I have tried keeping the buttonAction functionality in the class, but that didn't work, I have tried a multiple different ways but can't get my head around how to show it working. All other advice is given to implement using IBOutlets so this would be really helpful for me to understand. Thanks
Try something like this:
class ClickingCheckbox: UIButton {
convenience init() {
self.init(frame: .zero)
self.setImage(UIImage(named: "Empty_Checkbox"), for: .normal)
self.setImage(UIImage(named: "Checked_Checkbox"), for: .selected)
self.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
#objc private func buttonTapped() {
self.isSelected = !self.isSelected
}
}

How can I call a function that creates a button from another viewcontroller?

I have a function in my TuesdayViewController.swift that creates a button.
Whenever it's Tuesday, I want that button to appear in my ViewController.swift
I have this function in my TuesdayViewController:
func tuesdayView(){
let button = UIButton(frame: CGRect(x: 16, y: 200, width: 343, height: 45))
button.backgroundColor = .red
button.setTitle("Test button", for: .normal)
self.view.addSubview(button)
}
If I call this function in Tuesday's viewDidLoad(), the button shows in the TuesdayViewController.
How can I make it so I call this function through my main ViewController and for the button to show in the main ViewController screen?
I have tried this in my main ViewController but the button doesn't appear:
override func viewDidLoad(){
super.viewDidLoad()
TuesdayViewController().tuesdayVew()
}
Any help would be appreciated!
If I understand your question right, you just want to add the same kind of button from your TuesdayViewController into your MainViewController, and not adding the button to the TuesdayViewController by calling it in the MainViewController.
To do that, you just can declare your tuesdayView as a public property of your TuesdayViewController, like so:
TuesdayViewController.swift
class TuesdayViewController: UIViewController {
public lazy var tuesdayView: UIButton = {
let button = UIButton(frame: CGRect(x: 16, y: 200, width: 343, height: 45))
button.backgroundColor = .red
button.setTitle("Test button", for: .normal)
return button
}()
override func viewDidLoad(){
super.viewDidLoad()
self.view.addSubview(self.tuesdayView)
}
}
And call that property like what you've been doing before.
MainViewController.swift
class MainViewController: UIViewController {
override func viewDidLoad(){
super.viewDidLoad()
let button = TuesdayViewController().tuesdayView
self.view.addSubview(button)
}
}
You need to use an observer with NotificationCenter:
First you need to create a Notification Name
extension Notification.Name {
static let notName = Notification.Name("notName")
}
TuesdayViewController:
override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(tuesdayViewObserver), name: .notName, object: nil)
}
#objc func tuesdayViewObserver(_ notification: Notification) {
//Here you call the tuesdayView function
tuesdayView()
}
And in the controller in which you want to fire the method, you post the notification and the method will be executed:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.post(name: .notName, object: nil)
}
For further info, I recommend you to take a look to NotificationCenter and how it works. LINK

How to change UIButton's image every time it is pressed

How can I make a UIButton change image from A to B and again B to A, every time it's pressed?
Not as .normal to .highlighted, but permanent.
I've tried the .highlighted method because I can't find the code for permanent, here's my code:
func ChangeButton() {
Button.setImage(A, for: .normal)
Button.setImage(B, for: .highlighted)
Thanks for mentions of setBackgroundImage to Xavier L. from the other answer.
Try the following code:
import UIKit
class ViewController: UIViewController {
#IBOutlet var button: UIButton!
var buttonActive = false
override func viewDidLoad() {
super.viewDidLoad()
button.setBackgroundImage(UIImage(named: "apple"), for: .normal)
}
#IBAction func buttonPressed() {
if buttonActive {
button.setBackgroundImage(UIImage(named: "apple"), for: .normal)
} else {
button.setBackgroundImage(UIImage(named: "pineapple"), for: .normal)
}
buttonActive = !buttonActive
}
}
And your storyboard should look like that:
N.B. On Stack Overflow you should perform some actions before asking. Try to include some code you tried.
I recommend changing the backgroundImage because it's scaled automatically, and the button text in front won't get covered.
If it's a custom button, within its initializer:
self.addTarget(self, action: #selector(*yourfunctoswitchimages*), for: .touchUpInside)
... and then that yourfunctoswitchimages can just check what the current background image is, and switch it accordingly.
If it's not a custom button, add a target to it in viewDidLoad or something. Here's a lot of sample code.
In your viewDidLoad()
yourButt.addTarget(self, action: #selector(switcheroo), for: .touchUpInside)
Another func in your view controller:
func switcheroo()
{
if yourButt.currentBackgroundImage == image1
{
yourButt.setBackgroundImage(image2), for: .normal)
}
else { // ...set image to image1 }
}
yourButt would be a property of your view controller of course, that way it's accessible to the viewDidLoad() and to other funcs within it.

Button triggers another view

Right now I have this:
lazy var Button: UIButton = {
let tb = UIButton()
tb.backgroundColor = UIColor.yellowColor()
tb.clipsToBounds = true
tb.layer.cornerRadius = 39
tb.addTarget(self, action: #selector(showButton), forControlEvents: .TouchUpInside)
tb.setBackgroundImage(UIImage(named: "buttonMenu"), forState: UIControlState.Normal)
return tb
}()
How can I make the button take me to another view or do other stuff like opening the camera?
PS: The showButton function doesn't do anything really.
So you have
tb.addTarget(self, action: #selector(showButton), forControlEvents: .TouchUpInside)
but you need
tb.addTarget(self, action: #selector(className.showButton), forControlEvents: .TouchUpInside)
func showButton(sender:UIButton) {
//Code
}
I have tried this in 7.2.1 Xcode
import UIKit
import CoreLocation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let Button: UIButton = {
let tb = UIButton()
tb.frame = CGRectMake(0, 0, 100, 50)
tb.backgroundColor = UIColor.yellowColor()
tb.clipsToBounds = true
tb.layer.cornerRadius = 39
tb.addTarget(self, action: "showButton:", forControlEvents: .TouchUpInside)
// only change the action syntax like "action: "showButton:" "
return tb
}()
self.view .addSubview(Button)
// 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.
}
func showButton(sender:AnyObject?) {
//Code
}
}