I want to let user give +1 with one button or -1 points with another button, but they should be able to only press one of these buttons one time...
I use this code, but the user can still click on the button multiple times...
var job: Job! {
didSet {
jobLabel.text = job.text
likeButton.setTitle("π \(job.numberOfLikes)", for: [])
dislikeButton.setTitle("π \(job.numberOfDislikes)", for: [])
}
}
#IBAction func dislikeDidTouch(_ sender: AnyObject)
{
(dislikeDidTouch).isEnabled = false
job.dislike()
dislikeButton.setTitle("π \(job.numberOfDislikes)", for: [])
dislikeButton.setTitleColor(dislikeColor, for: []) }
#IBAction func likeDidTouch(_ sender: AnyObject)
{
sender.userInteractionEnabled=YES;
job.like()
likeButton.setTitle("π \(job.numberOfLikes)", for: [])
likeButton.setTitleColor(likeColor, for: [])
}
Since the sender is a UIButton , it's better to construct the funcs like this
#IBAction func dislikeDidTouch(_ sender: UIButton)
#IBAction func likeDidTouch(_ sender: UIButton)
and inside each one do
sender.isEnabled = false
Related
I am trying to repeat a song in my app. How can I put in a loop feature for this?
#IBAction private func handlePauseTouchUpInside(_ sender: UIButton) {
if player?.timeControlStatus == .paused {
player?.play()
isPause = false
playPauseButton.setImage(UIImage(imageLiteralResourceName: "ic-pause"), for: .normal)
rotateView()
} else {
player?.pause()
isPause = true
playPauseButton.setImage(UIImage(imageLiteralResourceName: "ic-play"), for: .normal)
}
}
//here function repeat
#IBAction private func repeatButtonTapped(_ sender: UIButton) {
enter code here
}
(Xcode Version 13.4.1 (13F100))
My prepareForSegue method isn't passing data to the destination view controller.
var buttonsDictionary = [Int: UIButton]()
func createButtonArray() {
for item in statTitles {
let statisticButton = StatButton()
statisticButton.layer.cornerRadius = 10
statisticButton.backgroundColor = UIColor.darkGray
statisticButton.setTitle(String(item.value), for: UIControlState.normal)
statisticButton.setTitleColor(UIColor.white, for: UIControlState.normal)
statisticButton.titleLabel?.font = UIFont.systemFont(ofSize: 43)
statisticButton.titleEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0)
statisticButton.contentHorizontalAlignment = .left
statisticButton.addTarget(self, action: #selector(displayStatDetail), for: .touchUpInside)
statisticButton.buttonIndex = item.key
buttonsDictionary[item.key] = (statisticButton) // Assign value at item.key
print(statisticButton.buttonIndex)
}
}
func viewSavedStatistics() {
for button in buttonsDictionary {
statisticsView.addArrangedSubview(button.value)
}
}
#objc func displayStatDetail() {
self.performSegue(withIdentifier: "StatDetailSegue", sender: UIButton())
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "StatDetailSegue" {
if let destinationVC = segue.destination as? StatDetailViewController,
let index = (sender as? StatButton)?.buttonIndex {
destinationVC.statID = index
print("Destination STATID: \(destinationVC.statID)")
}
}
}
All of the above code is written in the ViewController class.
StatButton is a custom UIButton class.
The prepare is meant pass on the buttonIndex of the tapped button, but only passes on 0 and doesn't print so I don't think it's being called.
You sender is a new instance of UIButton which doesn't have any of the information you need. Instead pass the button calling the selector.
#objc func displayStatDetail(_ sender: StatisticButton) {
self.performSegue(withIdentifier: "StatDetailSegue", sender: sender)
}
You would need to change the target selector like this in the loop.
statisticButton.addTarget(self, action: #selector(displayStatDetail(_:)), for: .touchUpInside)
Youβre passing a new instance of UIButton as sender here:
self.performSegue(withIdentifier: "StatDetailSegue", sender: UIButton())
Instead you should probably have your statisticButton there. Your button target selector method can have a parameter - the button instance the user clicked on. Use it as sender.
You had a mistake in performSeguefunction you've send always a new object of UIButton, not the one you've clicked on. Here is what you should do.
statisticButton.addTarget(self, action: #selector(displayStatDetail(_ :)), for: .touchUpInside)
#objc func displayStatDetail(_ sender: UIButton) {
self.performSegue(withIdentifier: "StatDetailSegue", sender: sender)
}
I am a beginner and the following is what code I have so far. When clicking the button, it'll switch between the checkmark and the empty box (that's good). However, when exiting the app, the button won't save the state of being selected (check marked).
Attached is all my code, so that you can clearly see what's going on.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var checkMarkButton: UIButton!
let save = "save"
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.bool(forKey: "save") == true {
checkMarkButton.setImage(#imageLiteral(resourceName: "greyChecked"), for: .normal)
}else{
checkMarkButton.setImage(#imageLiteral(resourceName: "greyUnchecked"), for: .normal)
}
}
#IBAction func checkMarkAction(_ sender: UIButton) {
UserDefaults.standard.set(true, forKey: "save")
}
}
video of what is happening
Give the image name directly ,I tested my answer it is working
override func viewDidLoad() {
super.viewDidLoad()
if UserDefaults.standard.bool(forKey: "checkBoxSave01") == true {
checkBoxButton1.setImage(#imageLiteral(resourceName: "id"), for: .normal)
}else{
checkBoxButton1.setImage(#imageLiteral(resourceName: "phone"), for: .normal)
}
}
var isFirstClick = true
#IBAction func checkBoxTapped(_ sender: UIButton) {
if isFirstClick{
checkBoxButton1.setImage(#imageLiteral(resourceName: "id"), for: .normal)
UserDefaults.standard.set(true, forKey: "checkBoxSave01")
ifFirstClick = false
}else{
checkBoxButton1.setImage(#imageLiteral(resourceName: "phone"), for: .normal)
UserDefaults.standard.set(false, forKey: "checkBoxSave01")
isFirstClick = true
}
}
Once you click on button checkBoxSave01key value will be true until you delete the app.
I tried to get the title of a button in swift like below.
#IBAction func buttonAction(_ sender: Any) {
let buttonTitle = sender.titleForState(.Normal)!
}
but it didn't work,even it doesn't give any hint when we press . after the sender.
so what is the correct way of doing this in swift 3.0
Or else if we create an IBOutlet and then we use its currentTitle, it works fine like below. Why we cannot get it with sender. for above
#IBOutlet var thebutton: UIButton!
#IBAction func buttonAction(_ sender: Any) {
let buttonTitle = thebutton.currentTitle!
print(buttonTitle)
}
Because parameter sender is in type Any instead of UIButton. Change the method signature to:
#IBAction func buttonAction(_ sender: UIButton) {
if let buttonTitle = sender.title(for: .normal) {
print(buttonTitle)
}
}
and you should be good to go.
Smartest version using Swift 5.0:
#IBAction func buttonAction(_ sender: UIButton) {
print(sender.currentTitle)
}
To get the title of the button regardless of its current state in swift 3.0 try using this:
#IBAction func buttonPressed(_ sender:UIButton){
let buttonTitle = sender.titleLabel?.text
print("\(String(describing: buttonTitle)")
}
This will return the title for the state, based on the state that the button is current in.
In order to resolve the warning, following code may be used.
#IBAction func buttonAction(_ sender: UIButton) {
let buttonTitle = sender.title(for: .normal) ?? String()
print(buttonTitle)
}
Using Swift version 5.5.2, the best way I found out to print a label's title is:
#IBAction func keyPressed(_ sender: UIButton) {
print(sender.title(for: .normal)!)
}
I was receiving a warning while using sender.title(for: .normal). The exclamation mark (!) solved it.
#IBAction func buttonPressed(_ sender: AnyObject) {
let title = sender.title(for: .normal)
print("\(title) button pressed")
}
So this is for swift 4.0, not the last one.
If your button has a regular title you can use:
button.title(for: state) // probably UIControl.State.normal
If your UIButton has an attributed title you'll need to use:
self.attributedTitle(for: state)
Or you can use a more general extension:
extension UIButton {
func titleForState(_ state: UIControl.State = .normal) -> String? {
if let title = self.title(for: state) {
return title
}
if let attribTitle = self.attributedTitle(for: state) {
return attribTitle.string
}
return nil
}
}
I used switch statment:
var buttonConter = 1
#IBAction func hardlessSelected(_ sender: UIButton) {
switch buttonConter {
case 1:
buttonConter += 1
print("Soft")
case 2:
buttonConter += 1
print("Medium")
case 3:
buttonConter += 1
print("Hard")
default:
print("Non")
}
}
}
The simple way just to use currentTitle:
#IBAction func hardlessSelected(_ sender: UIButton) {
print(sender.currentTitle)
}
Instead of using the currentTitle of the UIButton to get the name, you can use titleLabel.
The easy way to get this done is to unwrap the titleLabel then unwrap the text:
#IBAction func buttonAction(_ sender: UIButton) {
var buttonTitle = sender.titleLabel!.text!
print(buttonTitle)
}
Since Swift 3.0, it changed from
sender.titleForState(.Normal)! >> sender.title(for : .normal)!
Change Any to AnyObject.
#IBAction func buttonPressed(_ sender: AnyObject) {
let title = sender.title(for: .normal)!
print("\(title) button pressed")
}
#IBAction func btnNextTapped(_ sender: Any) {
let title = (sender as AnyObject).title(for: .normal)!
}
Swift4.0
I have a HMSegmentedControl with 4 segments. When it is selected, it should pop up view. And when the pop up dismissed, and trying to click on same segment index it should again show the pop up. By using following does not have any action on click of same segment index after pop up dissmissed.
segmetedControl.addTarget(self, action: "segmentedControlValueChanged:", forControlEvents: UIControlEvents.ValueChanged)
You can add the same target for multiple events.
So lets say your segmentedControlValueChanged: looks like this:
#objc func segmentedControlValueChanged(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
// value for first index selected here
}
}
Then you can add targets for more than 1 events to call this function:
segmentedControl.addTarget(self, action: #selector(segmentedControlValueChanged(_:)), for: .valueChanged)
segmentedControl.addTarget(self, action: #selector(segmentedControlValueChanged(_:)), for: .touchUpInside)
Now your function will get called when a value was changed and when the user releases his finger.
with sender, use the sender name sender when you want to access in the action:
segmentControl.addTarget(self, action: #selector(changeWebView(sender:)), for: .valueChanged)
or
addTarget(self, action: #selector(changeWebView), for: .valueChanged)
Swift 5
// add viewController
#IBOutlet var segmentedControl: UISegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
segmentedControl.addTarget(self, action: #selector(CommentsViewController.indexChanged(_:)), for: .valueChanged)
}
// using change
#objc func indexChanged(_ sender: UISegmentedControl) {
if segmentedControl.selectedSegmentIndex == 0 {
print("Select 0")
} else if segmentedControl.selectedSegmentIndex == 1 {
print("Select 1")
} else if segmentedControl.selectedSegmentIndex == 2 {
print("Select 2")
}
}
You set your target to fire just when the value change, so if you select the same segment the value will not change and the popover will not display, try to change the event to TouchUpInside, so it will be fired every time you touch inside the segment
segmentedControl.addTarget(self, action: #selector(segmentedControlValueChanged(_:)), for: .touchUpInside)
#IBAction func segmentedControlButtonClickAction(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
print("First Segment Select")
}
else {
print("Second Segment Select")
}
}
Swift4 syntax :
segmentedControl.addTarget(self, action: "segmentedControlValueChanged:", for:.touchUpInside)
Drag and drop create an action which is a value type.
#IBAction func actionSegment(_ sender: Any) {
let segemnt = sender as! UISegmentedControl
print(segemnt.selectedSegmentIndex)// 0 , 1
}