I'm trying to save button image inside button view. Here is briefly what my code looks like:
I have a UITableView with button in it. Whenever I press the button the image changes. I change the image using this code:
First I use:
cell.checkmarkButton.addTarget(self, action:
#selector(subscribeTapped(_:)), for: .touchUpInside)
to recognize when the image is tapped. Then I use:
#objc func subscribeTapped(_ sender: UIButton) {
selectedButton = String(sender.tag)
if let ButtonImage = sender.image(for: .normal),
let Image = UIImage(named: "WhiteCheckMarkButton"),
ButtonImage.pngData() == Image.pngData()
{
sender.setImage( UIImage.init(named: "GreenCheckMarkButton"), for: .normal)
} else {
sender.setImage( UIImage.init(named: "WhiteCheckMarkButton"), for: .normal)
}
Inside my subscribeTapped function to change the image. All good it changes the image but I can't seem to find out how to save once the image has changed. It seems really confusing to me. I can definitely do it if the image is not in a tableView using UserDefaults. But inside a tableView I have no idea what should I do.
Related
I am just learning Swift and am trying to toggle a button based on a user action between two images. It would be nice to just check the name of the images showing and toggle to the other one.
I am able to get the image from the button but not necessarily it's name. My question is how to compare it to the image name in Swift.
func toggleImage(){
var img = self.sendButton.image(for: .normal)//NO ERROR
if img.isEqual(image-one) {
//ERROR HERE
//switch to image-two
} else {
//switch to image-one
}
}
Thanks in advance for any suggestions.
There is a better way. Treat the button like a checkbox. The unchecked state is image 1, the checked state is image 2.
To setup a UIButton to work like a checkbox, use the isSelected property.
sendButton.setImage(UIImage(named: "image1"), for: .normal)
sendButton.setImage(UIImage(named: "image2"), for: .selected)
// You may also need to set the image for the highlighted selected state.
sendButton.setImage(UIImage(named: "image2"), for: [.selected, .highlighted])
Now that the button knows about both images, you can switch between the to using the isSelected property.
func toggleImage() {
sendButton.isSelected = !sendButton.isSelected
}
Using ===
private let image-one = UIImage(named: "name1")
private let image-two = UIImage(named: "name2")
override func viewDidLoad() {
sendButton.setImage(image-one, for: .normal)
}
func toggle image() {
if self.sendButton.currentImage === image-one {
.....
}
}
Using flags (less elegant, but much safer):
enum WhichImage {
case image-one, image-two
}
private var whichImage: WhichImage = .image-one
Instead of checking images you check whichImage and update it when image is changed.
Set Images in Interface approach the just change state of button in code.
Here is the code to change the state
#IBAction func fastButtonAction(_ sender: Any) {
fastButton.isSelected = !fastButton.isSelected
}
You need to get image name and compare it like below
if self.sendButton.currentImage == UIImage(named: "image-one") {
//switch to image-two
}else {
//switch to image-one
}
I'm new to iOS dev and I've been trying to toggle a button/checkbox in my tableviewcell by tapping the cell. My code is pretty naive, switching to the 'check' image works fine, but the issue is switching back to un-checked image when double tapping the cell.
What's not working in my code? Also is there a better way to do this? (perhaps via delegate funcs from the cell itself?)
Code examples would be very helpful! Thanks.
var isChecked:Bool = true
This following func is called in didSelectRowAtIndexPath func in my Tableview class.
let btnCheckBox:UIButton = cell.contactCheckbox
setState(button: btnCheckBox)
func setState(button: UIButton){
let check = UIImage(named: "check_green")
let unCheck = UIImage(named: "un_check_green")
if isChecked {
button.setImage(check, for: .normal)
isChecked = false
print("First Tap - Bool is \(isChecked)")
} else {
button.setImage(unCheck, for: .normal)
isChecked = true
print("Double Tap - Bool is \(isChecked)")
}
}
You should use UIButton , and set image for state of button, sample
check_green for selected
check_red for none
And each UITableviewcell must have an isSelected
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)
I have a 5 different buttons where I want the user to be able to select one if it’s not selected, and de-select it if it already is selected, while at the same time de-selecting another button if it is selected.
normal = button’s image when not selected filled = button’s image when selected
To do this I have created an if/else statement:
#IBAction func option1ButtonAction(sender: AnyObject) {
if (option1Button.currentImage == UIImage(named: "normal")) {
if option2Button.currentImage == UIImage(named: "filled") || option3Button.currentImage == UIImage(named: "filled") || option4Button.currentImage == UIImage(named: "filled") || option5Button.currentImage == UIImage(named: "filled") {
option1Button.setImage(filled, forState: .Normal)
option2Button.setImage(normal, forState: .Normal)
option3Button.setImage(normal, forState: .Normal)
option4Button.setImage(normal, forState: .Normal)
option5Button.setImage(normal, forState: .Normal)
}
else {
option1Button.setImage(filled, forState: .Normal)
}
}
else {
option1Button.setImage(normal, forState: .Normal)
}
}
Afterwards I made an if option1Button.currentImage == UIImage(named: "filled”) statement. Everything works exactly how I want it to, however I have one problem. Whenever the user presses the home button and then goes right back into the app, the buttons still have the “normal” image, even when clicked.
Inside the viewDidDisappear function I put the following code in hopes to fix this issue:
option1Button.setImage(normal, forState: .Normal)
option2Button.setImage(normal, forState: .Normal)
option3Button.setImage(normal, forState: .Normal)
option4Button.setImage(normal, forState: .Normal)
option5Button.setImage(normal, forState: .Normal)
But I still have the problem occurring. I would be grateful for any help provided.
You need change image from your button when clicked! I understand right?
For your issue I believe you can do different. I make a code for example.
First set image for state in button.
option1Button.setImage(normal, forState: UIControlState.Normal);
option1Button.setImage(filled, forState: UIControlState.Disabled);
option2Button.setImage(normal, forState: UIControlState.Normal);
option2Button.setImage(filled, forState: UIControlState.Disabled);
Second I made a function, this function change state of your button.
selectButton(button:UIButton)
{
option1Button.enabled = button != option1Button;
option2Button.enabled = button != option2Button;
}
Now you just do implement this way you action, and other detail is you don't need more create a function for every button ex. #IBAction func option1ButtonAction(sender: AnyObject) only create one action #IBAction func onButtonClicked(sender: AnyObject) and like all buttons here... remember only increment your buttons in your selectButton(button:UIButton) function, or if preferrer you can create a collection and push your button there and do a while in selectButton
#IBAction func onButtonClicked(sender: AnyObject) {
if let clickedButton = sender as? UIButton{
selectButton(clickedButton);
}
}
If I understood correctly your issue, I hope helped you!
If Too long, my problem is : When i click on the play of button of a cell and want to change the image of the pressed play button, some other cell's play button change too.
I'm creating an app where you can get Music preview and play them.
To display this, I use an UITableView with custom UITableViewCell containing a play button and some other things.
That's how it's looking.
So when i click on a Cell Play button, the right track is played but here's the problem : I try to change the backgroundImage of my button but other buttons image are changed too... And if I scroll my button even get back to the image it was using before I make the change...
The cell correctly shows the new image
But some other do it too...
And if I scroll up, my new image is remplaced by the older one...
Here's my function code :
func getPreview(sender : AnyObject){
var positionButton = sender.convertPoint(CGPointZero, toView: self.feedTable)
var indexPath = self.feedTable.indexPathForRowAtPoint(positionButton)
var rowIndex = indexPath!.row
var cell = feedTable.cellForRowAtIndexPath(indexPath!)
var bouton: UIButton = cell?.valueForKey("postPlay") as! UIButton
if sender.title == "Mettre l'extrait en pause" {
mediaPlayer.pause()
sender.setTitle("Jour l'extrait", forState: UIControlState.Normal)
var playImage = UIImage(named: "playIcon")
sender.setImage(playImage, forState: UIControlState.Normal)
}
if rowIndex == bouton.tag{
var songLink = post[rowIndex].valueForKey("previewLink") as! String
let url = NSURL(string: songLink)
mediaPlayer.contentURL = url
mediaPlayer.play()
bouton.setTitle("Mettre l'extrait en pause", forState: UIControlState.Normal)
var pauseImage = UIImage(named: "pauseIcon")
bouton.setImage(pauseImage, forState: UIControlState.Normal)
}
}
Could you help me to find what's wrong ? Thank you !
UITableViewCells are reused, not stored offscreen until you need one for the same index path again. So each time a cell is displayed, -tableView:cellForRowAtIndexPath: is called, and you're responsible for completely setting up the cell. Every time. You can't assume a state you've previously set up for a cell at that index path is still intact.