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)
}
}
}
Related
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
I would to do a programmed button without the storyboard. The problem is that I can not call the button in a separate function like I can when I drag and drop a UIButton from a storyboard into a view controller. I do not want to use the storyboard at all.
//Trying to Create a var for btn
override func viewDidLoad() {
super.viewDidLoad()
let btn = UIButton(type: .custom) as UIButton
btn.backgroundColor = .blue
btn.setTitle("Button", for: .normal)
btn.frame = CGRect(x: 100, y: 100, width: 200, height: 100)
btn.addTarget(self, action: #selector(clickMe), for: .touchUpInside)
self.view.addSubview(btn)
}
#objc func clickMe(sender:UIButton!) {
print("Button Clicked")
}
func place() {
//do something to btn.
}
Read about variable scopes. In the question you have declared your button inside the method/function which restricts the scope of its usage within the method. When you declare the variable within the scope of the class/struct you can use it within other methods/functions.
let btn = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
btn.backgroundColor = .blue
// .. other settings here
self.view.addSubview(btn)
}
#objc
func clickMe(sender:UIButton) {
print("Button Clicked")
}
func place() {
btn.backgroundColor = .red
}
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!
I have the following buttons which are adding dynamically based on some condition. Now i need to change all added buttons behaviour as radio buttons. so that I can do some actions based on the selection..
var posX = 0
var posY = 0
if trim.contains("0"){
print("contaim 0")
let button1 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button1.setTitleColor(UIColor.blackColor(), forState: .Normal)
button1.setTitle("No", forState: .Normal)
button1.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button1.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button1)
posX = 60
}
if trim.contains("1") {
print("contaim 1")
let button2 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button2.setTitleColor(UIColor.blackColor(), forState: .Normal)
button2.setTitle("Less", forState: .Normal)
button2.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button2.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button2)
posX = posX + 60
}
if trim.contains("2"){
print("contaim 2")
let button3 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button3.setTitleColor(UIColor.blackColor(), forState: .Normal)
button3.setTitle("Half", forState: .Normal)
button3.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
button3.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button3)
posX = posX + 60
}
I have set the buttonAction methods as below buts its not working
func buttonAction(sender: UIButton!) {
print("Button tapped")
sender.setImage(UIImage(named: "checkboxredtick.png")!, forState: .Normal)
}
let buttons = [UIButton]()
// create button1
let button1 = UIButton(frame: CGRect(x: posX, y: posY, width: 60, height: 20))
button1.setTitleColor(UIColor.blackColor(), forState: .Normal)
button1.setTitle("No", forState: .Normal)
button1.setImage(UIImage(named: "checkbox untick.png")!, forState: .Normal)
// if the selected button cannot be reclick again, you can use .Disabled state
button1.setImage(UIImage(named: "checkboxredtick.png")!, forState: .Selected)
button1.addTarget(self, action: #selector(buttonAction), forControlEvents: .TouchUpInside)
myStackview.addSubview(button1)
buttons.append(button1)
// create other buttons and add into buttons ...
func buttonAction(sender: UIButton!){
for button in buttons {
button.selected = false
}
sender.selected = true
// you may need to know which button to trigger some action
// let buttonIndex = buttons.indexOf(sender)
}
In case anyone finds this useful. Here is an example of how I use DLRadioButton library (https://github.com/DavydLiu/DLRadioButton) to create RadioButtons dynamically.
You can check a complete small project to show a working code in here https://github.com/omhack/DynamicRadioButtons
import UIKit
import DLRadioButton
//Delegate to manage the Polls
protocol QuestionsDialogDelegate : class{
func questionsAnswered(polls: [Poll])
}
class QuestionsDialog: UIViewController {
#IBOutlet weak var stackView: UIStackView!
#IBOutlet var rootView: UIView!
#IBOutlet weak var nestedView: UIView!
weak var delegate: QuestionsDialogDelegate?
var questions : [Question]!
var polls = [Poll]()
var serviceType : Int = 0
var indexView : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
//setting the stack view properties
stackView.alignment = UIStackViewAlignment.leading
stackView.axis = .vertical
}
//this is where the heavy logic, to create the dynamic radio buttons takes place
func showQuestions(){
if(questions.count <= 1){
rootView.frame.size.height = 200
nestedView.frame.size.height = 200
}else{
rootView.frame.size.height = 400
nestedView.frame.size.height = 400
}
for question in questions{
var otherButtons : [DLRadioButton] = []
let frame1 = CGRect(x: self.view.frame.size.width / 2 - 131, y: 350, width: 262, height: 17);
//we create a base radio button to use it as an anchor view
let firstRadioButton = createRadioButton(frame: frame1, title: "", color: UIColor.purple);
let label = UILabel()
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 17.0)
label.textColor = UIColor.darkGray.withAlphaComponent(0.85)
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.25
label.frame = CGRect(x: 0, y: 0, width: 200, height: 30)
label.text = question.question
self.stackView.insertArrangedSubview(label, at: self.indexView)
self.indexView += 1
let poll = Poll()
poll.idQuestion = question.idQuestion
var i = 0;
for answer in question.answers{
let frame = CGRect(x: self.view.frame.size.width / 2 - 131, y: 380 + 30 * CGFloat(i), width: 300, height: 17);
let radioButton = createRadioButton(frame: frame, title: answer.answer! + " ", color: UIColor.purple)
radioButton.tag = answer.idAnswer
radioButton.params["poll"] = poll
otherButtons.append(radioButton)
self.stackView.insertArrangedSubview(radioButton, at: self.indexView)
i += 1;
self.indexView += 1
}
firstRadioButton.otherButtons = otherButtons
firstRadioButton.isHidden = true
firstRadioButton.otherButtons[1].isSelected = true
}
}
//Method to create a custom button
private func createRadioButton(frame : CGRect, title : String, color : UIColor) -> MyDLUIButton {
let radioButton = MyDLUIButton(frame: frame);
radioButton.titleLabel?.translatesAutoresizingMaskIntoConstraints = false
radioButton.titleLabel!.font = UIFont.systemFont(ofSize: 14);
radioButton.setTitle(title, for: []);
radioButton.setTitleColor(UIColor.darkGray, for: []);
radioButton.iconColor = color;
radioButton.indicatorColor = color;
radioButton.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left;
radioButton.addTarget(self, action: #selector(QuestionsDialog.selectedAnswer(_:)), for: UIControlEvents.touchUpInside)
self.view.addSubview(radioButton);
return radioButton;
}
#objc func selectedAnswer(_ sender: MyDLUIButton){
let poll = sender.params["poll"] as? Poll
poll?.idAnswer = sender.tag
if let row = self.polls.index(where: {$0.idQuestion == poll?.idQuestion}) {
self.polls[row] = poll!
}else{
self.polls.append(poll!)
}
print("polls size: \(self.polls.count)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidDisappear(_ animated: Bool) {
if(self.polls.count < self.questions.count){
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "questionsDialogDismissed"), object: nil)
}
}
#IBAction func requestService(_ sender: UIButton) {
delegate?.questionsAnswered(polls: self.polls)
}
}
class MyDLUIButton: DLRadioButton{
var params: Dictionary<String, Any>
override init(frame: CGRect) {
self.params = [:]
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
self.params = [:]
super.init(coder: aDecoder)
}
}
I would create a tag for every UIButton, then add your UIButton to be send to your ButtonAction:
button.tag = 0
button.addTarget(object, action: #selector(YourViewController.buttonAction(_:)),
forControlEvents: .TouchUpInside)
func buttonAction(sender: UIButton!) {
let selectedButton = sender as! UIButton
print(selectedButton.tag) // here stands the correct button which is pressed
}
You could also create an Array containing all Buttons, for example:
let myButtons = [UIButton]()
let button1 = UIButton()...
button1.tag = 0
myButtons.add(button1)
And now change it like this way:
myButtons[0].setImage(.....)
Where 0 is your first button (so with tag 0) // you should set your tags in the same order in which you append it to your myButtons Array.
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.