Swift3: Add button with code - ios

Im reading Apples swift (iOS) documentation but its written for Swift 2 and i use Swift 3. I want to add a button programmatically but its seems there is a change and I can't find how to fix it.
Here is the Code for the Swift 2 example:
import UIKit
class RatingControl: UIView {
// MARK: Initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Buttons
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
button.backgroundColor = UIColor.red()
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)
addSubview(button)
}
override func intrinsicContentSize() -> CGSize {
return CGSize(width: 240, height: 44)
}
// MARK: Button Action
func ratingButtonTapped(button: UIButton){
print("Button pressed")
}
}
The only change i made after the 'fix-it' showed the error is this in the selector:
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(button:)), for: .touchDown)
This should have printed "Button pressed" but it doesn't. Any help?

My code:
button.backgroundColor = UIColor.red
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), for: .touchDown)
override var intrinsicContentSize : CGSize {
//override func intrinsicContentSize() -> CGSize {
//...
return CGSize(width: 240, height: 44)
}
// MARK: Button Action
func ratingButtonTapped(_ button: UIButton) {
print("Button pressed đź‘Ť")
}

Try something like this. I haven't tested but it should work:
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
button.backgroundColor = UIColor.red
button.addTarget(self, action: #selector(ratingButtonTapped), for: .touchUpInside)
addSubview(button)
func ratingButtonTapped() {
print("Button pressed")
}

Found the solution. For some reason the:
func ratingButtonTapped(button: UIButton)
needs an "_" before button. So it should be :
func ratingButtonTapped(_ button: UIButton)
And the other part of the code must be :
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), for: .touchDown)
Thanks for helping :) Your method may be correct also but thats the one Apple wants it.

Related

How to assign a button’s action in code using #objc mark for given function?

Hi for this question I found answer on How to create a button programmatically? however still facing the errors: "Argument of '#selector' cannot refer to local function 'plusOne(sender:)'" and "#objc can only be used with members of classes, #objc protocols, and concrete extensions of classes". If you can advice.
let button = UIButton()
button.frame = CGRect(x: 150, y: 300, width: 60, height: 60)
button.setTitle("Click", for: .normal)
button.setTitleColor(UIColor.blue, for: .normal)
button.addTarget(self, action: #selector(plusOne), for: .touchUpInside)
self.view.addSubview(button)
#objc func plusOne(sender: UIButton!) {
self.count += 1
self.label.text = "\(self.count)"
}
The problem you have is that you've nested the #objc func plusOne(sender: UIButton!) within viewDidLoad (which was why i asked the initial question about scope). You need to move it out to a class-scope method.
override func viewDidLoad() {
// all the usual stuff...
let button = UIButton()
button.frame = CGRect(x: 150, y: 300, width: 60, height: 60)
button.setTitle("Click", for: .normal)
button.setTitleColor(UIColor.blue, for: .normal)
button.addTarget(self, action: #selector(plusOne), for: .touchUpInside)
self.view.addSubview(button)
}
#objc func plusOne(sender: UIButton!) {
self.count += 1
self.label.text = "\(self.count)"
}
The name of the method is plusOne(sender:), the argument labels make part of the name

How to create a button programmatically with for loop in swift

I created buttons with for loop and i want to print button number when pressed to button. How can i do this?
for x in 0..<5 {
let button = UIButton(frame: CGRect(x: CGFloat(x) * view.frame.size.width + 10 , y: 40, width: view.frame.size.width - 20, height: 30))
buttonKontrol = x
print(buttonKontrol)
button.setTitle("Button", for: .normal)
button.backgroundColor = .white
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(btntapped), for: .touchUpInside)
scrollView.addSubview(button)
}
and objc func:
#objc func btntapped(_ sender: UIButton) {
print("button tapped")
}
Various ways to do that...
find the frame of the tapped button (not a good approach, but for your simple example it could work)
use the .tag property of the button
evaluate the .currentTitle property of the button
add the buttons to an array... on tap, use let buttonNumber = btnsArray.firstIndex(of: sender)
There are lots of ways, but a 'Swifty' way might be like this:
final class TargetAction {
let work: () -> Void
init(_ work: #escaping () -> Void) {
self.work = work
}
#objc func action() {
work()
}
}
class ViewController: UIViewController {
private var tas: [TargetAction] = []
override func viewDidLoad() {
super.viewDidLoad()
(0...4).forEach { x in
let button = UIButton(frame: CGRect(x: CGFloat(x) * 50 , y: 40, width: 44, height: 44))
button.setTitleColor(.black, for: .normal)
button.setTitle("\(x)", for: .normal)
let ta =
TargetAction {
print(x)
}
tas.append(ta)
button.addTarget(ta, action: #selector(TargetAction.action), for: .touchUpInside)
view.addSubview(button)
}
}
}

How can I override this class function?

I have an extension class, where I'm extending UIButton like below, it's working fine.
extension UIButton {
class func backButtonTarget(_ target: Any, action: Selector) -> UIBarButtonItem {
let backButton = UIButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(58), height: CGFloat(15)))
backButton.setTitle("Cancel",for: .normal)
let barBackButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(target, action: action, for: .touchUpInside)
return barBackButtonItem
}
}
But now, I need to change its title for some view controller, so I was thinking of its overriding, but failed. How can be this be overridden, so that I can change its title?
Extensions can not/should not override.
It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide.
Extensions can add new functionality to a type, but they cannot override existing functionality.
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html
You can subclass the bar button Item like
class CustomBarButtonItem: UIBarButtonItem {
override func awakeFromNib() {
super.awakeFromNib()
customize()
}
func customize() {
frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(58), height: CGFloat(15))
// Add more as per requirement
}
}
Make title a String parameter for the function, so you can call it and provide a custom title.
class func backButtonTarget(_ target: Any, action: Selector, title: String) -> UIBarButtonItem {
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 58, height: 15))
backButton.setTitle(title, for: .normal)
let barBackButtonItem = UIBarButtonItem(customView: backButton)
backButton.addTarget(target, action: action, for: .touchUpInside)
return barBackButtonItem
}
}

Stuck with adding target to button programmatically

I've created a UIButton and I want it to print some message when it's pressed.
So I did something like this:
In loadView()
button.addTarget(self, action: #selector(ViewController.pressButton(button:)), for: .touchUpInside)
A method:
func pressButton(button: UIButton) {
NSLog("pressed!")
}
But nothing happens when I click the button.
Add the button code in your viewDidLoad and it will work for you:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = UIColor.gray
button.addTarget(self, action: #selector(pressButton(button:)), for: .touchUpInside)
self.view.addSubview(button)
}
func pressButton(button: UIButton) {
NSLog("pressed!")
}
You don´t need to add ViewController.pressButton to selector, it´s enough with the function name.
Swift 4.x version:
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = .gray
button.tag = 0
button.addTarget(self, action: #selector(pressButton(_:)), for: .touchUpInside)
self.view.addSubview(button)
#objc func pressButton(_ button: UIButton) {
print("Button with tag: \(button.tag) clicked!")
}
Swift 5.1 version:
let button = UIButton(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
button.backgroundColor = .gray
button.tag = 100
button.addTarget(self, action: #selector(pressButton), for: .touchUpInside)
self.view.addSubview(button)
#objc func pressButton(button: UIButton) {
print("Button with tag: \(button.tag) clicked!")
}
try this in Swift3!
button.addTarget(self, action: #selector(self.pressButton(button:)), for: .touchUpInside)
#objc func pressButton(button: UIButton) { NSLog("pressed!") }
Use the following code.
button.addTarget(self, action: #selector(FirstViewController.cartButtonHandler), for: .touchUpInside)
Your class name corresponds to FirstViewController
And your selector corresponds to the following function
func cartButtonHandler() {
}
In swift 3 use this -
object?.addTarget(objectWhichHasMethod, action: #selector(classWhichHasMethod.yourMethod), for: someUIControlEvents)
For example(from my code) -
self.datePicker?.addTarget(self, action:#selector(InfoTableViewCell.datePickerValueChanged), for: .valueChanged)
Just give a : after method name if you want the sender as parameter.
You mention that the addTarget call is in loadView(). Is this in your custom subview, of some kind, or the viewController?
From your selector, it's targeting a method in your ViewController class, but if the target for this action is the view itself, then it would make sense that the action is not going through.
If you declare your button in a viewController, and in viewDidLoad add this target as above, then the message should be printed as you're looking for. I believe you are "targetting" the wrong class with your action.
let cancelButton = UIButton.init(frame: CGRect(x: popUpView.frame.size.width/2, y: popUpView.frame.size.height-20, width: 30, height: 30))
cancelButton.backgroundColor = UIColor.init(patternImage: UIImage(named: cancelImage)!)
cancelButton.addTarget(self, action: #selector(CommentsViewController.canceled), for:.touchUpInside)
Add the button code in override func viewDidLoad() method
Make sure your action handler tagged with #IBAction like this:
#IBAction func pressButton(button: UIButton) {
print("pressed!")
}
Then it will work!

UIButton will not respond

I'm currently working through Apple's Swift tutorial. In it, i am trying to make a custom button respond to tap and in turn print to the console. It seems to not be responding at all to any taps, or at the very least will not print it's response to the console.
Code is below, if anymore is needed please let me know.
import UIKit
class RatingControl: UIView {
//MARK: Initializaion
required init?(coder aDecoder: NSCoder) { // overrides it's superclass implementation of the initializer
super.init(coder: aDecoder)
let button = UIButton(frame: CGRect(x:0, y:0, width: 44, height: 44))
button.backgroundColor = UIColor.redColor()
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchDown)
addSubview(button)
func intrensicContentSize() -> CGSize {
return CGSize(width: 240, height: 44)
}
}
//MARK: Button Action
func ratingButtonTapped(button:UIButton) {
print("will it print?")
}
}
Please try .TouchUpInside instead of TouchDown
button.addTarget(self, action: #selector(RatingControl.ratingButtonTapped(_:)), forControlEvents: .TouchUpInside)

Resources