I have a button in a tableview cell. I want that initially the button has an image "A", when the user clicks on it, it changes to "B", when the user clicks on it again it changes back to "A".
Let the two images to be "A" and "B" in this scenario
Wherever the button is:
button.addTarget(self, action: "pressed:", forControlEvents: .TouchUpInside)
button.setImage(UIImage(named: "a.png")!, forState: .Normal)
button.tag = 999
func pressed(sender: UIButton!) {
if sender.tag == 999 {
sender.setImage(UIImage(named: "b.png")!, forState: .Normal)
sender.tag = 0
} else {
sender.setImage(UIImage(named: "a.png")!, forState: .Normal)
sender.tag = 999
}
}
You can add tag to the button.
// This code comes in viewDidLoad
button.tag = 1 // for A
button.titleLabel.text = "A"
// On-click of the button, check the tag and change the name
if button.tag == 1
{
button.tag = 2
button.titleLabel.text = "B"
}
Subclass UIButton, add click handler in this class and make reference in Interface Builder. Then, create boolean property in your class, which you will trigger in click handler every time. In didSet of this property set proper image
If we are just dealing with two states then this solution is easier and less messy. You can simply use UIButton states.
You can assign different images for default state and selected state in storyboard itself.
func pressed(sender:UIButton){
sender.selected = !sender.selected
}
This will just change the states and images will be displayed depending on state.
Related
I have a agree button below two checkbox. i want to enable the agree button and also change the colour of agree button after both checkbox is checked. i have used custom images for checkbox.
i am using this code
This is my UIButton class
let selectedImage = UIImage(named: "checkbox_checked")
let unselectedImage = UIImage(named: "checkbox_unchecked")
class Qbutton: UIButton {
//Bool Property
var isChecked:Bool = false{
didSet{
if isChecked {
self.setImage(selectedImage, forState: UIControlState.Normal)
}else{
self.setImage(unselectedImage, forState: UIControlState.Normal)
}
}
}
override init(frame: CGRect){
super.init(frame:frame)
self.layer.masksToBounds = true
self.setImage(unselectedImage, forState: UIControlState.Normal)
self.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
self.isChecked = false
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
func buttonClicked(sender: UIButton) {
if(sender == self){
if isChecked == true{
isChecked = false
print("true")
self.setImage(unselectedImage, forState: UIControlState.Normal)
}else{
isChecked = true
print("false")
self.setImage(selectedImage, forState: UIControlState.Selected)
}
NSUserDefaults.standardUserDefaults().setObject(isChecked, forKey: "isBtnChecked")
NSUserDefaults.standardUserDefaults().synchronize()
}
}
}
AND THIS IS MY VIEW CONTROLLER CLASS WHERE I AM USING QBUTTON CLASS
checkBoxOne = Qbutton(frame: CGRectMake(X,Y,WIDTH,HEIGHT))
isChecked = NSUserDefaults.standardUserDefaults().boolForKey("isBtnChecked")
checkBoxOne.isChecked = isChecked
self.view.addSubview(checkBoxOne)
checkBoxTwo = Qbutton(frame: CGRectMake(X,Y,WIDTH,HEIGHT))
checkBoxTwo.isChecked = isChecked
self.view.addSubview(checkBoxTwo)
NOW I WANT TO CHANGE THE COLOR OF AGREE BUTTON IF USER CHECK BOTH THE CHECKBOXES.
There is a problem with your logic of the QButton. You are storing the checked state in user defaults property isBtnChecked. But there are multiple instances of QButton (2 checkboxes), so even one is checked the property will be set to true. Avoid storing the state of the checkbox in defaults and instead query the state from checkBoxOne and checkBoxTwo using their is isChecked property.
Check if both check box button selected is true then update your agree botton accordingly.
If this button just contains text, you can use the code:
button.setTitleColor(UIColor.redColor(), forState: .Normal)
=> Take array for storing state of check button state. By default array contain "0" value for all elements , means if you have 5 checkboxes than array contain [#"0",#"0",#"0",#"0",#"0"] . now whenever button press , alter the state of button in array. so that if 2nd button pressed , and i have "0" state for that button than i replace "0" with "1" and check if array contain all "1" value than change the colour of agree button.
=> comment below if not understand any thing what i said.
I have a scrollview inside a view. Inside the scrollview I create programmatically 5 buttons. Every button loads a different image with a different tag each one. I added a function that is called when pressing the buttons.
let avatarsListScrollingView = avatarsListView(CGSizeMake(70.0, 55.0), avatarCount: 5)
func avatarsListView(buttonSize:CGSize, avatarCount:Int) -> UIView {
**CODE**
for i in 0...(avatarCount-1) {
let button = UIButton(type: .Custom)
**CODE**
button.setImage(UIImage(named: avatarsList[i]), forState: .Normal)
button.tag = i
button.addTarget(self, action: "avatarListSelected:", forControlEvents: .TouchUpInside)
avatarButtonView.addSubview(button)
}
return avatarButtonView
}
Then when pressing the buttons, I call to "avatarListSelected":
func avatarListSelected(sender:UIButton){
if let image = sender.imageView?.image?.imageWithRenderingMode(.AlwaysTemplate) {
sender.setImage(image, forState: .Normal)
sender.tintColor = UIColor.redColor()
}
self.addAvatarView.reloadInputViews()
}
This function tints the image button to red, it is working fine, but the problem is that when I press some other button, I want the other one goes to the original color. Right now every button that I press gets in red.
I tried to add the call to "self.addAvatarView.reloadInputViews()" to try to "redraw" again all the buttons, but never gets called.
Do you guys know some way to do this?
Thanks to everybody!
This is the final code that solved the problem:
func avatarListSelected(sender:UIButton){
print(sender.tag)
if let image = sender.imageView?.image?.imageWithRenderingMode(.AlwaysTemplate) {
sender.setImage(image, forState: .Normal)
sender.tintColor = UIColor.redColor()
}
for view in self.avatarButtonView.subviews as [UIView] {
if let btn = view as? UIButton {
if btn.tag != sender.tag {
btn.setImage(UIImage(named: avatarsList[btn.tag]), forState: .Normal)
}
}
}
}
Create a property selectedButton: UIButton? and keep a reference to the selected button there. Don't forget to update it in avatarListSelected method and before you change it, if it isn't nil, change its color to original (and then change it).
If the buttons have different original colors, subclass UIButton class and keep the original color there.
I don't know if is better approach or answer, but, i maybe could delivery this using this approach:
Create a method that will "fill" the color for your choice button and "clear" color to others , but its a method that loop through UIScrollView and look for each UIButton. Something like this :
func setBackgroundColorButton(color:UIColor , buttonTag:Int){
for view in self.scrollView.subviews as [UIView] {
if let btn = view as? UIButton {
if btn == buttonTag {
btn.tintColor = color
} else {
btn.tintColor = UIColor.whiteColor()
}
}
}
}
This is the concept, i didn't tested, but maybe just need adjust to search inside your scroll view or similar.
But with this will be work nice i believe :D
You could do it like this
for i in 0...5 {
let button = UIButton(type: .Custom)
let x = 50 * i + 10
let y = 50
button.frame = CGRectMake(CGFloat(x), CGFloat(y), 40, 40)
button.setTitle("\(i)", forState: .Normal)
button.tag = i
button.backgroundColor = UIColor.greenColor()
button.tintColor = UIColor.blueColor()
button.addTarget(self, action: "avatarListSelected:", forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
func avatarListSelected(sender : UIButton){
sender.backgroundColor = UIColor.orangeColor()
for view in self.view.subviews{
if(view.isKindOfClass(UIButton)){
let button = view as! UIButton
if button.tag != sender.tag{
button.backgroundColor = UIColor.greenColor()
}
}
}
}
The frame etc is just for demonstation purpose only, you should of course use your own value. The tintColor property is not valid for all button types. Read the documentation for more information.
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!
I have a button on my table view cell. I am returning numberOfRowsInSectionas return arrayname.count. therefore i get the same number of buttons as the array count.
I trigger a notification using that button, when the user presses that button again the notification gets canceled. It is a location based notification.
It works fine if if there is only one button in the table view. But when I return 2 or more cells, I can't seem to figure out how to distinguish between the button events without one affecting the other.
Example - there are two cells in the table and two buttons. One for location 'a' and one for location 'b'. I want a notification when i enter region 'a' so i press the button corresponding to location 'a'. but because button 'b' is not pressed the notification doesn't get scheduled. it works fine only if all the buttons are in the same state.
but,how can i solve this problem ?
`button.addTarget(self, action: "pressed:", forControlEvents: .TouchUpInside)
button.setImage(UIImage(named: "a.png")!, forState: .Normal)
button.tag = 999
func pressed(sender: UIButton!) {
if sender.tag == 999
{ sender.setImage(UIImage(named: "b.png")!, forState: .Normal)
sender.tag = 0 } else
{ sender.setImage(UIImage(named: "a.png")!, forState: .Normal) sender.tag = 999 }
}`
I am already using this code to switch images on button press.
I see no connection between the problem that you have and cell reusing.
The easiest way to detect which button is pressed is to add line:
button.tag = indexPath.row
to your cellForRowAtIndexPath function. Then in the function which is triggered by your buttons add:
func buttonPressed(sender:UIButton) {
let selectedItem = arrayname[sender.tag] // this gives you selected item from array
// or you can do
if sender.tag == 0 {
// button in first cell pressed
}
}
/*Buy settings the tag to your button you can identify which button is selected */
//create a button globally in your view controller
uibutton*menu
// add the below code in your cellForRowAtIndexPath method
[menus addTarget:self action:#selector(menuclick:) forControlEvents:UIControlEventTouchUpInside];
menus.tag=indexPath.row+1;
//identify button using button sender
(void)menuclick:(id)sender
{
NSInteger tagid=[sender tag];
if(checkbutton.isSelected)
{
//you can identify which button get selected
switch (tagid)
{
case 1:
//button 1 is selected
break;
case2:
//button 2 is selected
break;
default:
break;
}
[menu setSelected:NO];
}
else
{
//you can identify which button get unselected
switch (tagid)
{
case 1:
//button 1 is selected
break;
case2:
//button 2 is selected
break;
default:
break;
}
[menu setSelected:YES];
}
}
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();