Swift error with adding target - ios

Here is my code. I get an unrecognized selector sent to instance crash/error every time I tap addButton. I've looked for the past hour for an answer and can't find one. Please help.
#IBOutlet var addButton: UIButton!
#IBOutlet var resetButton: UIButton!
var number:Int = 0
override func viewDidLoad() {
super.viewDidLoad()
let size: CGSize = self.view.frame.size;
countLabel.frame = CGRect(x: 0, y:0, width: size.width, height: size.height/4)
minusButton.frame = CGRect(x:0, y: size.height/4, width: size.width/2, height: size.height/8);
addButton.frame = CGRect(x:0, y:size.height/4 + size.height/8, width: size.width, height: 5*size.height/8)
resetButton.frame = CGRect(x:size.width/2, y: size.height/4, width: size.width/2 ,height: size.height/8)
addButton.addTarget(self, action: #selector(addNumber(sender:)), for: UIControlEvents.touchUpInside)
minusButton.addTarget(self, action: #selector(minusNumber), for: UIControlEvents.touchUpInside)
resetButton.addTarget(self, action: #selector(resetNumber), for: UIControlEvents.touchUpInside)
}
func addNumber(sender: UIButton!) {
number = number + 1
countLabel.text = String(number)
}

Change
addButton.addTarget(self, action: #selector(addNumber(sender:)), for: UIControlEvents.touchUpInside)
With
addButton.addTarget(self, action: #selector(addNumber), for: UIControlEvents.touchUpInside)

You don't need to include sender in a selector.
So you need to change your code to
addButton.addTarget(self, action: #selector(addNumber), for: .touchUpInside).
And you don't need to implicitly unwrap sender
func addNumber(sender: UIButton)

Add #objc keyword before selector declaration:
#objc func addNumber(sender: UIButton!) {
number = number + 1
countLabel.text = String(number)
}

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

Key board will show notification. does not give notification of keyboard appearing

I have the following notification setup in my viewDidLoad() of my custom keyboard extension:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
and this is the function I call outside of my viewDidLoad():
#objc func keyboardWillShow(_ notification: NSNotification) {
if let keyboardRect = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
print(keyboardRect.height)
ScreenHeight = Int(keyboardRect.height)
}
}
However, I set a breakpoint inside of my keyboardWillShow() function and it is never triggered. Is there something else I have to do to get the size of the keyboard before it shows?
I am trying to dynamically adjust the size of elements programmatically inserted into my keyboard.
Let me know if more information is necessary or if this is an obvious fix.
Full Code:
class KeyboardViewController: UIInputViewController {
#IBOutlet var nextKeyboardButton: UIButton! = UIButton(type: .system)
var centralManager: CBCentralManager!
var NUB5: CBPeripheral!
var characteristics = [CBCharacteristic]()
var connection: UILabel = UILabel()
var serialNum: UILabel = UILabel()
var serial: String = ""
var ScreenHeight = 0
let cornerRadii = 4
//setup Number buttons
var num1: UIButton = UIButton()
var num2: UIButton = UIButton()
var num3: UIButton = UIButton()
var num4: UIButton = UIButton()
var num5: UIButton = UIButton()
var num6: UIButton = UIButton()
var num7: UIButton = UIButton()
var num8: UIButton = UIButton()
var num9: UIButton = UIButton()
var num0: UIButton = UIButton()
var spaceBar: UIButton = UIButton()
var plus: UIButton = UIButton()
var minus: UIButton = UIButton()
var back: UIButton = UIButton()
var left: UIButton = UIButton()
var right: UIButton = UIButton()
var period: UIButton = UIButton()
var comma: UIButton = UIButton()
var returnKey: UIButton = UIButton()
let screensize: CGRect = UIScreen.main.bounds
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardDidChangeFrameNotification, object: nil)
var keyboard: UIView!
func loadInterface() {
// load the nib file
var calculatorNib = UINib(nibName: "keyboard", bundle: nil)
// instantiate the view
keyboard = (calculatorNib.instantiate(withOwner: self, options: nil)[0] as! UIView)
// add the interface to the main view
view.addSubview(keyboard)
// copy the background color
view.backgroundColor = keyboard.backgroundColor
ScreenHeight = Int(self.accessibilityFrame.height)
print(ScreenHeight)
}
super.viewDidLoad()
loadInterface()
self.centralManager = CBCentralManager(delegate: self, queue: nil)
//Setup Labels
let width = screensize.width
let height = CGFloat(200) //subtract 10 from total screensize to give space for connection indicator
let screensize = self.view.bounds.size
//ScreenHeight = Int(height)
connection.frame = CGRect(x: 0,y: 0,width: width,height: 10)
//TODO
serialNum.frame = CGRect(x: width/2+5, y:10,width: width/2 - 10,height:15)
spaceBar.frame = CGRect(x: width*4/5+4, y: height/4+10, width: width/5, height: height/4)
num1.frame = CGRect(x:width/5,y: 10, width: width/5,height: height/4)
num2.frame = CGRect(x:width*2/5,y: 10, width: width/5,height: height/4)
num3.frame = CGRect(x:width*3/5,y: 10, width: width/5,height: height/4)
num4.frame = CGRect(x:width/5+1,y: height/4+10, width: width/5,height: height/4)
num5.frame = CGRect(x:width*2/5+2,y: height/4+10, width: width/5,height: height/4)
num6.frame = CGRect(x:width*3/5+3,y: height/4+10, width: width/5,height: height/4)
num7.frame = CGRect(x:width/5+1,y: height/2+10, width: width/5,height: height/4)
num8.frame = CGRect(x:width*2/5+2,y: height/2+10, width: width/5,height: height/4)
num9.frame = CGRect(x:width*3/5+3,y: height/2+10, width: width/5,height: height/4)
num0.frame = CGRect(x:width*2/5+3,y: 3*height/4+10, width: width/5,height: height/4)
plus.frame = CGRect(x:0,y: 10, width: width/5,height: height/4)
minus.frame = CGRect(x:0,y: height/4+10, width: width/5,height: height/4)
back.frame = CGRect(x:width*4/5,y:10,width:width/5,height:height/4)
right.frame = CGRect(x: width*4/5+4, y: height/2+10, width: width/5, height: height/4)
left.frame = CGRect(x:0,y: height/2+10, width: width/5,height: height/4)
nextKeyboardButton.frame = CGRect(x:0,y: 3*height/4+10, width: width/5,height: height/4)
period.frame = CGRect(x:width/5,y: 3*height/4+10, width: width/5,height: height/4)
comma.frame = CGRect(x:width*3/5+2,y: 3*height/4+10, width: width/5,height: height/4)
returnKey.frame = CGRect(x:width*4/5+3,y: height*3/4+10, width: width/5,height: height/4)
num1.addTarget(self,action: #selector(addOne), for: .touchUpInside)
num2.addTarget(self,action: #selector(addTwo), for: .touchUpInside)
num3.addTarget(self,action: #selector(addThree), for: .touchUpInside)
num4.addTarget(self,action: #selector(addFour), for: .touchUpInside)
num5.addTarget(self,action: #selector(addFive), for: .touchUpInside)
num6.addTarget(self,action: #selector(addSix), for: .touchUpInside)
num7.addTarget(self,action: #selector(addSeven), for: .touchUpInside)
num8.addTarget(self,action: #selector(addEight), for: .touchUpInside)
num9.addTarget(self,action: #selector(addNine), for: .touchUpInside)
num0.addTarget(self,action: #selector(addZero), for: .touchUpInside)
spaceBar.addTarget(self,action: #selector(space), for: .touchUpInside)
plus.addTarget(self, action: #selector(plusSign), for: .touchUpInside)
minus.addTarget(self, action: #selector(minusSign), for: .touchUpInside)
back.addTarget(self, action: #selector(deleteOne), for: .touchUpInside)
left.addTarget(self, action: #selector(leftOne), for: .touchUpInside)
right.addTarget(self, action: #selector(rightOne), for: .touchUpInside)
nextKeyboardButton.addTarget(self, action: #selector(handleInputModeList(from:with:)), for: .allTouchEvents)
period.addTarget(self, action: #selector(addPeriod), for: .touchUpInside)
comma.addTarget(self, action: #selector(addComma), for: .touchUpInside)
returnKey.addTarget(self, action: #selector(returnButton), for: .touchUpInside)
num1.setTitle("1", for: .normal)
num2.setTitle("2", for: .normal)
num3.setTitle("3", for: .normal)
num4.setTitle("4", for: .normal)
num5.setTitle("5", for: .normal)
num6.setTitle("6", for: .normal)
num7.setTitle("7", for: .normal)
num8.setTitle("8", for: .normal)
num9.setTitle("9", for: .normal)
num0.setTitle("0", for: .normal)
spaceBar.setTitle("SPACE", for: .normal)
back.setTitle("<-", for: .normal)
plus.setTitle("+", for: .normal)
minus.setTitle("-", for: .normal)
left.setTitle("<", for: .normal)
right.setTitle(">", for: .normal)
nextKeyboardButton.setTitle("NEXT", for: .normal)
period.setTitle(".", for: .normal)
comma.setTitle(",", for: .normal)
returnKey.setTitle("Return", for: .normal)
num1.layer.cornerRadius = CGFloat(cornerRadii)
num2.layer.cornerRadius = CGFloat(cornerRadii)
num3.layer.cornerRadius = CGFloat(cornerRadii)
num4.layer.cornerRadius = CGFloat(cornerRadii)
num5.layer.cornerRadius = CGFloat(cornerRadii)
num6.layer.cornerRadius = CGFloat(cornerRadii)
num7.layer.cornerRadius = CGFloat(cornerRadii)
num8.layer.cornerRadius = CGFloat(cornerRadii)
num9.layer.cornerRadius = CGFloat(cornerRadii)
num0.layer.cornerRadius = CGFloat(cornerRadii)
spaceBar.layer.cornerRadius = CGFloat(cornerRadii)
plus.layer.cornerRadius = CGFloat(cornerRadii)
minus.layer.cornerRadius = CGFloat(cornerRadii)
back.layer.cornerRadius = CGFloat(cornerRadii)
left.layer.cornerRadius = CGFloat(cornerRadii)
right.layer.cornerRadius = CGFloat(cornerRadii)
nextKeyboardButton.layer.cornerRadius = CGFloat(cornerRadii)
period.layer.cornerRadius = CGFloat(cornerRadii)
comma.layer.cornerRadius = CGFloat(cornerRadii)
returnKey.layer.cornerRadius = CGFloat(cornerRadii)
num5.layer.borderWidth = CGFloat(1)
num1.setTitleColor(UIColor.black, for: .normal)
num2.setTitleColor(UIColor.black, for: .normal)
num3.setTitleColor(UIColor.black, for: .normal)
num4.setTitleColor(UIColor.black, for: .normal)
num5.setTitleColor(UIColor.black, for: .normal)
num6.setTitleColor(UIColor.black, for: .normal)
num7.setTitleColor(UIColor.black, for: .normal)
num8.setTitleColor(UIColor.black, for: .normal)
num9.setTitleColor(UIColor.black, for: .normal)
num0.setTitleColor(UIColor.black, for: .normal)
spaceBar.setTitleColor(UIColor.black, for: .normal)
plus.setTitleColor(UIColor.black, for: .normal)
minus.setTitleColor(UIColor.black, for: .normal)
back.setTitleColor(UIColor.black, for: .normal)
left.setTitleColor(UIColor.black, for: .normal)
right.setTitleColor(UIColor.black, for: .normal)
period.setTitleColor(UIColor.black, for: .normal)
comma.setTitleColor(UIColor.black, for: .normal)
nextKeyboardButton.setTitleColor(UIColor.black, for: .normal)
returnKey.setTitleColor(UIColor.black, for: .normal)
num1.backgroundColor = UIColor.white
num2.backgroundColor = UIColor.white
num3.backgroundColor = UIColor.white
num4.backgroundColor = UIColor.white
num5.backgroundColor = UIColor.white
num6.backgroundColor = UIColor.white
num7.backgroundColor = UIColor.white
num8.backgroundColor = UIColor.white
num9.backgroundColor = UIColor.white
num0.backgroundColor = UIColor.white
spaceBar.backgroundColor = UIColor.white
plus.backgroundColor = UIColor.white
minus.backgroundColor = UIColor.white
back.backgroundColor = UIColor.white
left.backgroundColor = UIColor.white
right.backgroundColor = UIColor.white
nextKeyboardButton.backgroundColor = UIColor.white
period.backgroundColor = UIColor.white
comma.backgroundColor = UIColor.white
returnKey.backgroundColor = UIColor.white
connection.text = "No Connection"
serialNum.text = "-"
connection.backgroundColor = UIColor.white
serialNum.backgroundColor = UIColor.white
connection.layer.cornerRadius = 4
serialNum.layer.cornerRadius = 4
self.view.addSubview(connection)
self.view.addSubview(serialNum)
self.view.addSubview(spaceBar)
self.view.addSubview(num1)
self.view.addSubview(num2)
self.view.addSubview(num3)
self.view.addSubview(num4)
self.view.addSubview(num5)
self.view.addSubview(num6)
self.view.addSubview(num7)
self.view.addSubview(num8)
self.view.addSubview(num9)
self.view.addSubview(num0)
self.view.addSubview(plus)
self.view.addSubview(minus)
self.view.addSubview(back)
self.view.addSubview(left)
self.view.addSubview(right)
self.view.addSubview(period)
self.view.addSubview(comma)
self.view.addSubview(nextKeyboardButton)
self.view.addSubview(returnKey)
}
#objc func returnButton(sender: UIButton){
textDocumentProxy.insertText("\n")
}
#objc func addPeriod(sender: UIButton){
textDocumentProxy.insertText(".")
}
#objc func addComma(sender: UIButton){
textDocumentProxy.insertText(",")
}
#objc func leftOne(sender: UIButton){
textDocumentProxy.adjustTextPosition(byCharacterOffset: -1)
}
#objc func rightOne(sender: UIButton){
textDocumentProxy.adjustTextPosition(byCharacterOffset: 1)
}
#objc func deleteOne(sender: UIButton){
textDocumentProxy.deleteBackward()
}
#objc func plusSign(sender: UIButton){
textDocumentProxy.insertText("+")
}
#objc func minusSign(sender: UIButton){
textDocumentProxy.insertText("-")
}
#objc func space(sender: UIButton){
textDocumentProxy.insertText(" ")
}
#objc func addOne(sender: UIButton){
textDocumentProxy.insertText("1")
textDocumentProxy.insertText(String(ScreenHeight))
}
#objc func addTwo(sender: UIButton){
textDocumentProxy.insertText("2")
}
#objc func addThree(sender: UIButton){
textDocumentProxy.insertText("3")
}
#objc func addFour(sender: UIButton){
textDocumentProxy.insertText("4")
}
#objc func addFive(sender: UIButton){
textDocumentProxy.insertText("5")
}
#objc func addSix(sender: UIButton){
textDocumentProxy.insertText("6")
}
#objc func addSeven(sender: UIButton){
textDocumentProxy.insertText("7")
}
#objc func addEight(sender: UIButton){
textDocumentProxy.insertText("8")
}
#objc func addNine(sender: UIButton){
textDocumentProxy.insertText("9")
}
#objc func addZero(sender: UIButton){
textDocumentProxy.insertText("0")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if self.centralManager.state == CBManagerState.poweredOn {
self.centralManager.scanForPeripherals(withServices: [lairdUUID], options: nil)
}
}
#objc func keyboardWillShow(_ notification: NSNotification) {
if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
let keyBoardRect = frame?.cgRectValue
ScreenHeight = Int(keyBoardRect!.height)
}
}
override func viewWillDisappear(_ animated: Bool) {
// super.viewWillDisappear(animated)
// if let centralManager = self.centralManager {
// if centralManager.state == CBManagerState.poweredOn {
// if let NUB5 = self.NUB5 {
// if peripheral.state == CBPeripheralState.connected {
// centralManager.cancelPeripheralConnection(NUB5)
// }
// }
// }
// }
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(_ textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(_ textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
}
For prevent crashes and for the best practice use
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
on viewWillAppear.
Since your method keyboardWillShow has a parameter you should change the syntax accordingly to inform the compiler exactly the method that it has to look for.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
What was happening is that the compiler will search for the method keyboardWillShow without any parameters which is not there, Hence doesn't execute anything.

How do i get the button value in swift 4?

#IBOutlet var button: UIButton!
func randomize(){
var x_axis:CGFloat = 8.0
var y_axis:CGFloat = 330.0
for selected_Synonym in selected_Synonyms {
button = UIButton.init(type: UIButtonType.custom) as UIButton
button.frame = CGRect(x: x_axis, y: y_axis, width: 400, height: 50)
button.backgroundColor = UIColor.black
button.setTitle(selected_Synonym as? String, for: UIControlState.normal)
button.setTitleColor(UIColor.white, for: [])
button.addTarget(self, action: Selector(("pressed:")), for: UIControlEvents.touchUpInside)
self.view.addSubview(button)
x_axis = 10.0
y_axis += 70.0
}
}
func pressed(sender: Any){
let buttonTitle = button.currentTitle
print(buttonTitle)
}
However when it runs and I press on a button I get the following error:
Thread 1: signal SIGABRT.
The program creates 5 buttons. I am new to swift and ios development would be very grateful if someone could help me out. Thank you.
You have several issues. To fix the crash, replace Selector(("pressed:")) with #selector(pressed). The use of Selector is very out-of-date. Always use #selector.
Next, remove the #IBOutlet var button: UIButton! line. You don't need it.
Then change:
button = UIButton.init(type: UIButtonType.custom) as UIButton
to:
let button = UIButton(type: .custom)
Then update your pressed function to:
#objc func pressed(sender: UIButton){
let buttonTitle = sender.currentTitle
print(buttonTitle)
}
Note the addition of #objc. This is required for any function being used with a target/selector. Also note that sender is now UIButton instead of Any. It's best to set the sender's type to match the proper type.
Here's all of your code with lots of little fixes:
func randomize() {
var xAxis: CGFloat = 8.0
var yAxis: CGFloat = 330.0
for selectedSynonym in selectedSynonyms {
let button = UIButton(type: .custom)
button.frame = CGRect(x: xAxis, y: yAxis, width: 400, height: 50)
button.backgroundColor = .black
button.setTitle(selectedSynonym, for: .normal)
button.setTitleColor(.white, for: .normal)
button.addTarget(self, action: #selector(pressed), for: .touchUpInside)
self.view.addSubview(button)
xAxis = 10.0
yAxis += 70.0
}
}
#objc func pressed(sender: UIButton){
let buttonTitle = sender.currentTitle
print(buttonTitle)
}
Use camelCase, not snake_case when naming variables and functions. Make use of Swift type inference.

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!

how to create radio buttons dynamically in swift?

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.

Resources