I am wanting to add sounds to my app. I have added a UIButton with two images, soundON and soundOFF.
When I call the sound settings in the app the first time, they toggle fine with each image.
However, when I return to the sound settings a second and subsequent time, it is like the soundOff images does not disappear when the soundOn image is displayed.
Odd as the code is so short and simple.
func soundButton() {
sounds = UIButton(frame : CGRect(x: 65, y: 70, width: 40, height:40))
sounds.setImage(UIImage(named : "soundON"), for : .normal)
sounds.setImage(UIImage(named : "soundOFF"), for : .selected)
sounds.showsTouchWhenHighlighted = true
sounds.addTarget(self, action: #selector(soundButtonTapped), for: .touchUpInside)
self.soundView.addSubview(sounds)
}
#objc func soundButtonTapped(_ sender: Any) {
sounds.isSelected.toggle()
isSoundOn.toggle()
}
I have added a video to show the issue as this will save a ton of typing.
http://www.reeflifeapps.com/soundError.mov
Any help is greatly appreciated.
update:
I had the button on a UIView that was hidden on startup of the puzzle. When the user pressed the "Sounds Settings" icon, the sound setting UIView was unhidden. I had the button on this func to unhide the sound settings. I moved it to viewDidLoad() and it fixed it.
I suggest you to define a boolean variable that keeps the current state of your button. Then, you should set current image of button according to the current state of the variable.
var isSoundOn = false
#objc func soundButtonTapped(_ sender: Any) {
isSoundOn.toggle()
if isSoundOn {
// your logic when sound on (set button selected image, action etc)
} else {
// logic when sound off (set button not selected image, action etc)
}
}
If you still want to use soundButton.isSelected as your boolean variable,do not define images for different states in soundButton.setImage(yourImage, for: .selected) and soundButton.setImage(yourImage, for: .normal) and define them as follows:
soundButton.setImage(soundButton.isSelected ? soundOnImage : soundOffImage, for: .normal)
One of those two approaches above can be used.
UPDATE:
As Lloyd Kaijzer stated, isSoundOn = !isSoundOn updated as isSoundOn.toggle()
Related
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 a button that contains a finger print image like the picture above. that fingerPrint button has a function to segue to viewController2. that fingerPrint button exists on the viewController1.
when the viewController1 is opened for the first time, I will get a data from the server, if I don't have that data, I shouldn't segue to viewController2 .
but sometimes we have an error as the response of my request. if I get the error response, then I want that finger button to be rectangular button that has 'Refresh' as the title and has different function to make request again to the server
how to achieve change the shape of existing UI Button?
class ViewController1 : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
getDataFromServer()
}
#IBAction func fingerPrintButtonDidPressed(_ sender: Any) {
}
func getDataFromServer() {
// send request to get data from server
}
}
It is usually best to do it either all in code or all in storyboard. To do it in storyboard I suggest one of the following:
Create 2 buttons and in code hide one or another depending on your state
Assign different images and texts for different button states (there is a dropdown in interface builder) and then change the state of a button in runtime
To do it in code overall I suggest simply changing the values.
Assume you have something like this:
enum ViewState {
case idle
case success
case failed
}
var state: ViewState = .idle {
didSet {
refreshButton()
}
}
Now you can set your state when you get a response or on any event needed. All you need to implement is refreshButton.
func refreshButton() {
switch state {
case .idle:
button.setTitle(nil, for: .normal)
button.setImage(fingerprintImage, for: .normal)
button.backgroundColor = .clear
case .success:
button.setTitle(nil, for: .normal)
button.setImage(fingerprintImage, for: .normal)
button.backgroundColor = .clear
case .failed:
button.setTitle("REFRESH", for: .normal)
button.setImage(nil, for: .normal)
button.backgroundColor = .green
}
}
You can then use the same switch inside your button action (on press).
if isError
{
button.type = .system
button.backgroundColor - UIColor.green
button.setTitle("REFRESH" for: .normal)
button.addTarget(--------)
}
else
{
button.type = .custom
button.setImage(UIImage(named: "yourImageName.png") for: .normal)
button.addTarget(--------)
}
Simple Solution is : Use two buttons one for figure Image second for Refresh text. And use button isHidden property vice-versa.
For Auto layout
If you are using Auto layout then use constraint IBOutlet and change it's constant property value. it will change your button height or width.
For Auto resize
if you are using Auto resize than you can change you button frame which you want
I'm new to Swift and I'm trying to change the button colour on tap. When the button is tapped, it should change colour and when released it should go back to the original button colour.
An example of this is the calculator. When you tap a button, it changes from light grey to dark grey and when the user removes their finger off the button, it goes back to the original light grey colour. How do I go about doing that?
So far, I've only got this..
#IBAction func changeButtonColourOnTouch(sender: UIButton) {
zeroButton.backgroundColor = UIColor.blueColor()
}
The above code changes the button colour to blue but stays blue.
The problem is, after releasing the button, you should return the color to the original state.
You can link direct from storyboard, in the action TouchUpInside (release) and TouchDown (press) , to change the button color to the correct state in each event.
Or you can add a Target in the button by code, linking to the functions, as the code bellow shows it.
zeroButton.addTarget(self, action: Selector("holdRelease:"), forControlEvents: UIControlEvents.TouchUpInside);
zeroButton.addTarget(self, action: Selector("HoldDown:"), forControlEvents: UIControlEvents.TouchDown)
//target functions
func HoldDown(sender:UIButton)
{
zeroButton.backgroundColor = UIColor.blueColor()
}
func holdRelease(sender:UIButton)
{
zeroButton.backgroundColor = UIColor.whiteColor()
}
Code adapted by the present in the link UIButton with hold down action and release action
The checked answer above works, but if the user holds down on the button, then drags out, the background color won't return to normal. It's a tiny UI bug, but a simple fix. This includes the code of the checked answer.
zeroButton.addTarget(self, action: #selector(holdRelease), for: .touchUpInside);
zeroButton.addTarget(self, action: #selector(heldDown), for: .touchDown)
zeroButton.addTarget(self, action: #selector(buttonHeldAndReleased), for: .touchDragExit)
//target functions
#objc func heldDown()
{
zeroButton.backgroundColor = .blue
}
#objc func holdRelease()
{
zeroButton.backgroundColor = .white
}
#objc func buttonHeldAndReleased(){
zeroButton.backgroundColor = .blue
}
you could also use a tap gesture and change the color of the button as the user is tapping on the button
you could see apple documentation regarding UIGestureRecognizer in here
it is a little bit advanced, but you will learn a lot from it.
You can also use setbackgroundImageForState to define color image as button background for all UIControlState you are interested in e.g. Normal, Highlighted, Disabled, Selected.
let cx = UIGraphicsGetCurrentContext()
let color = UIColor.redColor()
let state = UIControlState.Selected
UIGraphicsBeginImageContext(CGSize(width:1, height:1))
CGContextSetFillColorWithColor(cx, color.CGColor)
CGContextFillRect(cx, CGRect(x:0, y:0, width:1, height:1))
let colorImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.zeroButton.setBackgroundImage(colorImage, forState: state)
Now color changes automatically and you don't have to handle it manually.
If you want that for a programmatically defined button, just declare the button of type system during its initialisation:
let button = UIButton(type: .system)
When I first run my app, I retrieve a number from my server and display it for my UIButton label. Think of this as a notification number displayed on a red UIButton.
When I remove a notification within the app, I want my UIButton label decrement by 1. I am able to get the decremented number from the server after I delete a notification, but I can't display this new number on the UIButton. The button always displays the number when the app is first fired.
I call makeButtonView() method after I remove a notification to update the UIButton
func makeButtonView(){
var button = makeButton()
view.addSubView(button)
button.tag = 2
if (view.viewWithTag(2) != nil) {
view.viewWithTag(2)?.removeFromSuperview()
var updatedButton = makeButton()
view.addSubview(updatedButton)
}else{
println("No button found with tag 2")
}
}
func makeButton() -> UIButton{
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
API.getNotificationCount(userID) {
data, error in
button.setTitle("\(data)", forState: UIControlState.Normal)
}
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}
Use this code for Swift 4 or 5
button.setTitle("Click Me", for: .normal)
I need more information to give you a proper code. But this approach should work:
lazy var button : UIButton = {
let button = UIButton(frame: CGRectMake(50, 5, 60, 40))
button.setBackgroundImage(UIImage(named: "redBubbleButton"), forState: .Normal)
button.addTarget(self, action: "targetController:", forControlEvents: UIControlEvents.TouchUpInside)
return button
}()
func makeButtonView(){
// This should be called just once!!
// Likely you should call this method from viewDidLoad()
self.view.addSubview(button)
}
func updateButton(){
API.getNotificationCount(userID) {
data, error in
// be sure this is call in the main thread!!
button.setTitle("\(data)", forState: UIControlState.Normal)
}
}
There have been some updates since Swift 4. This works for me:
self.button.setTitle("Button Title", for: UIControl.State.init(rawValue: 0))
Replace button with your IBOutlet name. You can also use a variable or array in place of the quoted text.
It's fairly simple ...
import UIKit
class ViewController: UIViewController {
#IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.setTitle("hello world", forState: UIControlState.Normal)
}
}
I believe if you set the state to normal, the value will propagate by default to other states so long as you haven't explicitly set a title for those states.
Said differently, if you set it for normal, it should also display this title when the button enters additional states
UIControlState.allZeros
UIControlState.Application
UIControlState.Disabled
UIControlState.Highlighted
UIControlState.Reserved
UIControlState.Selected
Lastly, here's Apple's documentation in case you have other questions.
Since your API call should be running on a background thread you need to dispatch your UI update back to the main thread like this:
DispatchQueue.main.async {
button.setTitle(“new value”, forState: .normal)
}
After setting the title, just a simple redraw of the button will do:
button.setNeedsDisplay();
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.