How do i get the button value in swift 4? - ios

#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.

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)
}
}
}

Change Color of Programmatically Created Button when Pressed

I'm using a function to create multiple buttons for my game.
func createButton() {
let button = UIButton()
button.setTitle("", for: .normal)
button.frame = CGRect(x:15, y: 50, width: 200, height:100)
button.backgroundColor = UIColor.red
self.view.addSubview(button)
button.addTarget(self, action: Selector(("buttonPressed:")), for:
.touchUpInside)
}
I call this function once for testing in viewDidLoad function, but I don't know what code I should put into my buttonPressed() function for the color of my button to change? I tried doing
self.backgroundColor = UIColor.blue
but that didn't work. I also tried using UIButton and button instead of self, but both of those didn't work either. What should I do?
Your code isn't clean Swift 4 code. Here's how to do this:
Create your button like you are, but change Selector to #selector:
func createButton() {
let button = UIButton()
button.setTitle("", for: .normal)
button.frame = CGRect(x:15, y: 50, width: 200, height:100)
button.backgroundColor = UIColor.red
self.view.addSubview(button)
button.addTarget(self, action: #selector((buttonPressed)), for: .touchUpInside)
}
Use the sender that is automatically added:
#objc func buttonPressed(sender: UIButton) {
sender.backgroundColor = UIColor.blue
}
Additionally may I offer a few suggestions?
Check the background color before changing it. No sense in needlessly changing a button that is already blue.
Since you aren't setting the title to your button, set the tag property (you can even add this as a parameter to createButton). This way you can know which button was tapped.
Just make the button an instance property.
let changingButton = UIButton()
func createButton() {
changingButton.backgroundColor = UIColor.red
changingButton.addTarget(self, action: #selector(buttonPressed), for: .touchUpInside)
}
#objc func buttonPressed() {
changingButton.backgroundColor = UIColor.blue
}

Swift error with adding target

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)
}

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