I have the following code for a button label title (btnTD) which toggles its label title between "L" and "R" AFTER which it is meant to use the UPDATED Label title in a function called by another button's action (btnCalculate in this case).
Both the toggling of the label and the function called by btnCalculate work fine.
However, when I toggle the button, the function is using the button's title label BEFORE it is changed, not AFTER it is changed, even though the UI is showing the title toggling correctly.
It doesn't matter what order I put the toggling of the label or the function called by btnCalculate, the result is always the same.
#IBAction func btnTD(_ sender: UIButton) {
if btnTD.titleLabel!.text! == "R" {
btnTD.setTitle("L", for: .normal)
} else {
btnTD.setTitle("R", for: .normal)
}
btnCalculate.sendActions(for: .touchUpInside)
}
Here is the code for btnCalculate.sendActions(for: .touchUpInside) although I don't think it is relevant
#IBAction func btnCalculate(_ sender: UIButton) {
txtOutput.text = Hold(IBTrk: Int(txtIBT.text!)!, TD: (btnTD.titleLabel!.text!) , OBTime: Double(txtOBTime.text!)!, TAS: Double(Int(txtTAS.text!)!), WD: Int(txtWD.text!)!, WS: Double(txtWS.text!)!)
}
Just use btnTD.currentTitle Not tiltleLabel.Text
#IBAction func btnCalculate(_ sender: UIButton) {
txtOutput.text = Hold(IBTrk: Int(txtIBT.text!)!, TD: (btnTD.currentTitle) , OBTime: Double(txtOBTime.text!)!, TAS: Double(Int(txtTAS.text!)!), WD: Int(txtWD.text!)!, WS: Double(txtWS.text!)!)
}
Setting the button title does so for the .normal state. However the button is being pressed at this time so for a moment (while calculate function is called) its title is still the old value.
Using a global variable in the view controller is one way around this:
// Declare outside a method (in viewController)
var buttonState: String = "L" // Could also be a Bool variable
// Button action
#IBAction func btnTD(_ sender: UIButton) {
if buttonState == "L" {
buttonState = "R"
btnTD.setTitle("R", for: .normal)
} else {
buttonState = "L"
btnTD.setTitle("L", for: .normal)
}
// Then call the calculate method
btnCalculate.sendActions(for: .touchUpInside)
}
Note: btnCalculate.sendActions() might be better as a separate function that is called here and also from btnCalculate button, rather than using sendActions.
Related
I created a UIButton within a for-loop because the number of these button depend on a certain number in the database. However, I have to change the image of this button after it is clicked, which doesn't work.
What I have done is I tried holding an array of those buttons and trying to access the buttons like that, which I don't think is not working.
let buttonArray: [UIButton] = [UIButton]()
...extra code
for (index, num) in numberOfButtonsNeeded.enumerated() {
let button = UIButton()
button.tag = index
button.addTarget(self, action: #selector(self.tap(sender:)), for: .touchUpInside)
buttonArray.append(button)
}
...
#objc func tap(sender: UIButton) {
DispatchQueue.main.asnyc{
buttonArray[sender.tag].setImage(UIImage(named:"Somename"))
}
}
I can access the tap gesture but this button's image won't be reset. Is there a way I can access the button? I do not think this array works.
This is suspect:
#objc func tap(sender: UIButton) {
DispatchQueue.main.asnyc{
buttonArray[sender.tag].setImage(UIImage(named:"Somename"))
}
You are already on the main queue, and the sender is the button that was tapped. So you don't need the array.
#objc func tap(sender: UIButton) {
sender.setImage(UIImage(named:"Somename"))
}
This question already has an answer here:
Why does Xcode line-out autocomplete methods for selector?
(1 answer)
Closed 2 years ago.
I have a UIButton within a UITableViewCell. When I call addTarget on the button and attempt to put a function in, the autocomplete has the function crossed out with a white line (see first image). Xcode still allows me to put the function in and run the app; however, when the button is tapped the function isn't called.
Button initialization:
private let infoButton: UIButton = {
let button = UIButton()
button.backgroundColor = .clear
button.adjustsImageWhenHighlighted = false
button.setImage(Images.sizeGuide, for: .normal)
button.addTarget(self, action: #selector(infoButtonPressed(_:)), for: .touchUpInside)
return button
}()
Function (infoButtonPressed):
#objc private func infoButtonPressed(_ sender: UIButton) {
print("Button Pressed")
}
Because I reuse this cell multiple times and only one of these cells needs to have this button, I have a variable that dictates whether or not to show the button:
var hasInfoButton: Bool = false {
didSet {
if hasInfoButton {
setupInfoButton()
}
}
}
The function that is called above simply sets up the button using autoLayout. Something to mention: when I tried calling addTarget in this function, the app crashed with Unrecognized selector sent to instance...
The tableView in which this is embedded in is only static and displays data. Therefore, allowSelection and allowsMultipleSelection are both set to false.
Does anyone have a solution to this?
You shouldn't need (_ sender: UIButton) the method should just be:
#objc func infoButtonPressed() {
print("button pressed")
}
EDIT:
The button initializer is also a little strange. The way I generally go about this kind of thing is like this:
let button = UIButton()
private func configureButton() {
button.backgroundColor = .clear
button.adjustsImageWhenHighlighted = false
button.setImage(Images.sizeGuide, for: .normal)
button.addTarget(self, action: #selector(infoButtonPressed(_:)), for: .touchUpInside)
}
Then call configureButton() in viewDidLoad()
I'm new to swift and the iOS platform in general, but I think I have a decent grasp on it.
I'm attempting to make a simple Bingo game, but I've run into a little issue.
I need to give the user the ability to deselect a number. Right now, I've got buttons that the user will click on to to change that piece to marked (giving it a background image). However, I want to change the image to nothing if they press the button again.
For the life of me, I can't seem to figure out how to check, preferably with an IF statement, whether the button has been pressed the first time or not. I was trying to use an IF statement to compare the image with something like this:
#IBAction func action(_ sender: AnyObject) {
if UIImage(named:"MarkedPiece") == true {
// labels for Numbers will be hidden here
} else {
sender.setImage(UIImage(named: "MarkedPiece"), for: UIControlState())
}
}
The above is the function that all of the buttons point to. I get the error message telling me that I can't compare type UIImage to BOOL, which makes sense. Is there another way that I should do it?
Any help would be appreciated!
You can set button image for normal state and selected state.
btn.setImage(UIImage(named: ""), for: .normal)
btn.setImage(UIImage(named: ""), for: .selected)
and use .isSelected
#IBAction func action(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
// labels for Numbers will be hidden here
} else {
}
}
I have two UIButtons that I want to use to set an A/B value to a variable before I save data to a database. I want a button to become selected when tapped, and deselected when the other button is tapped, and vice versa. What is a good solution for accomplishing this programmatically or in Interface Builder?
In order to set an "A/B value" as you mention, the easiest option would be to use a UISwitch or -in the general case of possibly more than 2 options- a UISegmentedControl (as #rmaddy suggested in the question's comments) .
These controls have built-in the "choose just one out of many" functionality that you are looking for.
The drawbacks of the switch are:
It has to be either on or off (does not support a selection state of "neither A nor B")
You can't have separate title labels for each state.
If you still want two separate UIButton instances, you can:
Have references to both buttons in your view controller (#IBOutlets wired using Interface Builder), e.g.:
#IBOutlet weak var leftButton: UIButton!
#IBOutlet weak var rightButton: UIButton!
Implement the action method for both buttons in such a way that it sets the selected state of the tapped button, and resets the other one. For example:
#IBAction func buttonAction(sender: UIButton) {
if sender == leftButton {
leftButton.isSelected = true
rightButton.isSelected = false
} else if sender == rightButton{
leftButton.isSelected = false
rightButton.isSelected = true
}
}
This is a quick-and-dirty solution for just two buttons. If you want a generic radio group of n-buttons, there are open source solutions on GitHub, etc...
Try this.
First create both button separate #IBOutlet.
#IBOutlet weak var btnYes: UIButton!
#IBOutlet weak var btnNo: UIButton!
Set Both Button Tag Like this and you also set tag using storyboard.
override func viewDidLoad() {
super.viewDidLoad()
btnYes.tag = 1
btnNo.tag = 2
}
Implement Common #IBAction method for both buttons
#IBAction func btnYesNoTapped(_ sender: UIButton) {
if sender.tag == 1 {
self.IsBtnSelected(isSelect: true, with: self.btnYes)
}else {
self.IsBtnSelected(isSelect: true, with: self.btnNo)
}
}
Create Custome Method
func IsBtnSelected(isSelect:Bool,with sender:UIButton){
self.btnYes.isSelected = false
self.btnNo.isSelected = false
sender.isSelected = isSelect
}
you can use following function for creating a radio button behaviour, you have to btn outlet to be selected and array of both outlets to this function. instead ofcolor you can also compare images and set images. for getting a required value yo can create a variable in viewcontroller and assign this variable a value in IBAction of btn and you can call this function from IBAction.
func radioButton(_ btnToBeSelected: UIButton, _ btnArray: [UIButton]) {
for btn in btnArray {
if btn == btnToBeSelected {
btn.backgroundColor = UIColor.black
//selected btn
//You can also set btn images by
//btn.setImage(<#T##image: UIImage?##UIImage?#>, for: <#T##UIControlState#>)
} else {
btn.backgroundColor = UIColor.red
//not selected btn
}
}
}
In iOS , you would have to do it manually.See the below approaches,
Use a switch . Using a UISwitch would be better if the option indicates a on/off state.
Use a same method when the button is pressed. Whenever the method gets called deselect the other button/buttons and select the pressed button. You can use tags or keep a reference of the buttons to differentiate between them.
Lastly , keep different methods for each buttons . Just deselect the other buttons whenever the button is pressed.
You can follow the above approaches by using interface builder or programmatically.
You can achieve it like below
I have implemented it for dates which are in TableView you just need to do little modifications
enum filterDateSelectableOptions:Int {
case AssignDate
case DueDate
case CompletionDate
}
//Assign Date selected by default
var currentSelectedFilterDate:filterDateSelectableOptions = .AssignDate
Now
func btnRadioButtonTapped(sender:UIButton) {
switch sender.tag {
case kTableViewRow.AssignDate.rawValue:
self.currentSelectedFilterDate = .AssignDate
case kTableViewRow.DueDate.rawValue:
self.currentSelectedFilterDate = .DueDate
case kTableViewRow.CompletionDate.rawValue :
self.currentSelectedFilterDate = .CompletionDate
default:
break;
}
//sender.isSelected = !sender.isSelected
self.tblFilterList.reloadData()
}
in cellForRow I have
// THIS IS DIFFERENT ENUM SO +1 is required in my case
case .AssignDate,.DueDate,.CompletionDate :
let button = buttonRadioCircle
button.tag = row.rawValue
cell.accessoryView = button
button.addTarget(self, action: #selector(btnRadioButtonTapped(sender:)), for: .touchUpInside)
button.isSelected = self.currentSelectedFilterDate.rawValue + 1 == row.rawValue
}
Basically, I have a three buttons on my main screen.
When I select one of these buttons, I would like the text on the selected button to change to bold and change color (blue).
When I select a different button, I would like the newly selected button to change to bold and change color(blue), and the previously selected button to go back to normal. (non-bold and black text)
I have these buttons sending an action to the script.
This is what I have, I can't seem to get it to work. Help would be much appreciated!
#IBAction func buttonOne(sender: UIButton){
sender.setTitleColor(UIColor.blueColor(), forState: UIControlState.Highlighted)
}
I have tried .Highlighted and .Selected on the UIControlState, neither seem to work. I have also tried the following, but I cant get it to work.
#IBAction func buttonOne(sender: UIButton){
sender.titleLabel?.textColor = UIColor.blueColor()
}
I figured that since the sender was a UIButton, and it was the button that was clicked, taking the values off of it and resetting them would work. I do believe I am missing something.
Thank you
Sounds like you want UIControlState.Normal
Selected does nothing in most cases, and Highlighted is only while you're pressing the button.
See more info here: https://developer.apple.com/library/ios/documentation/uikit/reference/uicontrol_class/index.html#//apple_ref/doc/constant_group/Control_State
Maybe you can do with a transform...
#IBAction func buttonPressed(sender: UIButton) {
sender.titleLabel!.textColor = UIColor.blueColor()
sender.transform = CGAffineTransformMakeScale(0.8, 0.8)
}
#IBAction func buttonReleased(sender: UIButton) {
sender.titleLabel!.textColor = UIColor.redColor()
sender.transform = CGAffineTransformIdentity
}
Provide tags to all buttons, connect each button actions to same function and try the following code:
#IBAction func butnClicked (sender : UIButton) {
for tg in 1...2 {
print(sender.tag)
let tmpButton = self.view.viewWithTag(tg) as? UIButton
if tmpButton?.tag == sender.tag {
tmpButton?.setTitleColor(.red, for: .normal)
} else {
tmpButton?.setTitleColor(.gray, for: .normal)
}
}
Hope will be helping.