The UIButton has a normal/default, highlighted, and selected image. I then have a IBAction method that is called on Touch Down. The method changes the highlighted image depending if it's selected. But when the button is selected, the method is called and so the highlight image is changed, however what is displayed is the normal/default image with a tint. I have tested that image used is in not nil. What happens is when the UIButton in a selected state is pressed displays the normal state with a tint. Why is it not using the highlight image and is there another way of showing a selected highlight image?
Why do you set the highlighted state in the IBAction method? You only need to set the highlighted image for you button when you create it. It will switch automatically. Adding a tint when selected is the default behavior of 'selection' when no highlighted image is assigned.
if your using Interface Builder, just assign the highlighted image there.
Im assuming your looking for normal button selection behavior with your IBAction method set to the touchUpInside event.
I got around this problem by using the selected state and notifications (not via the UI). When a notification is called I change image for the default state, change the selected state and then change the image for selected state.
Update:
I came up with a much better idea from another question that was doing something similar to me. The way to do it is to things in setSelected
- (void)setSelected:(BOOL)selected
{
if ( selected )
{
[self setImage:[CFCHStyleSheet imageForTickButtonChecked] forState:UIControlStateNormal];
[self setImage:[CFCHStyleSheet imageForTickButtonChecked] forState:UIControlStateSelected];
[self setImage:[CFCHStyleSheet imageForTickButtonCheckedDisabled] forState:UIControlStateDisabled];
}
else
{
[self setImage:[CFCHStyleSheet imageForTickButtonUnchecked] forState:UIControlStateNormal];
[self setImage:[CFCHStyleSheet imageForTickButtonUnchecked] forState:UIControlStateSelected];
[self setImage:[CFCHStyleSheet imageForTickButtonUncheckedDisabled] forState:UIControlStateDisabled];
}
[super setSelected:selected];
}
Related
I've gone through all the other questions concerning button color changes. Here's the situation, I have a button that when pressed causes a view to slide out. Before press the button's image is white, once pressed goes grey (this is acceptable), but when pressed again to return to original location, the image is still grey. I want it back to white and have tried using UIControlStateNormal, Disabled, etc with no success.
[self.button setImage:[UIImage imageNamed:#"someImage"] forState:UIControlStateNormal];
this has been changed to all UIControl types. currently it is set as:
[self.menu setImage:[UIImage imageNamed:#"menu"] forState:UIControlStateNormal];
[self.menu setImage:[UIImage imageNamed:#"menu"] forState:UIControlStateSelected | UIControlStateHighlighted];
and still no luck. Any suggestions?
You can disable adjusting colours of button's subviews by setting property
myButton.adjustsImageWhenHighlighted = false
you have to set the same image for both states of the button : -
self.button.setImage(ImageName, for: .normal)
self.button.setImage(ImageName, for: .highlighted)
The code you have shown simply declares which image the button will be depending on different states, however you will need to physically change the state of the button too so these images can be used for each state.
What I mean by this, is if you have the button show a different image for when the button is selected, you will need to change the button state to selected. To return the image to the original unselected image, you will need change the state back to unselected. For example, let's say within your viewDidLoad method you have the following code to declare the images for each of the button states:
//Set for normal state
[self.button setImage:[UIImage imageNamed:#"normalImage.png"] forState:UIControlStateNormal];
//Set for selected state
[self.button setImage:[UIImage imageNamed:#"selctedImage.png"] forState:UIControlStateSelected];
Now within your IBAction method you can toggle between the states
-(IBAction*)yourButtonIsPressed:(id)sender{
if (!self.button.selected){ //This is checking button state
//The code will run in here if the button is in a normal, unselected state. This is where you have you method here to slide in view etc
//Now change the button to a selected state
self.button.selected = YES;
}else{
//The code will now run in here if the button is already in a selected state and this is where you place your method to return the view etc
//Now set the button back to an unselected state
self.button.selected = NO;
}
}
I hope this helps
It was something completely overlooked. I had the view opacity set. so:
self.layer.opacity = .60;
was the issue. Once I commented that line out, the button works like a charm. Thanks for the help Jim.
If you created the button programmatically make sure to set the type and change the image render mode to use original to maintain the image color.
let image = UIImage(named: "someImage").withRenderingMode(.alwaysOrigianl)
let button = UIButton(type: .system)
I have a custom UICollectionViewCell that holds a UIButton with an image set. The purpose of this bottom is to allow users who are shopping via the app to add items to a list of their favourite items.
I have 2 versions of the image. One is a default greyed out heart and the other is a black heart. When a user taps to add an item to their favourites this method is fired:
Method fired on tap of heart:
- (void)addToFavouritesButtonTapped
{
NSLog(#"add to favourites button tapped");
}
In my cellForItemAtIndexPath method for my UICollectionView I have this:
_addToFavouritesButton = [cell addFavouriteButton];
[_addToFavouritesButton addTarget:_thisController action:#selector(addToFavouritesButtonTapped) forControlEvents:UIControlEventTouchUpInside];
Upon tapping the heart to save an item to favourites I'd like the image to change to my highlighted version which is the black heart.
How can I achieve this?
Set the other image as the one for the UIControlStateSelected and then when the button is tapped set the button to selected= YES, this will then change the image.
_addToFavouritesButton = [cell addFavouriteButton];
[_addToFavouritesButton addTarget:_thisController action:#selector(addToFavouritesButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[_addToFavouritesButton setImage:blackHeart forState:UIControlStateSelected];
- (void)addToFavouritesButtonTapped:(UIButton *)sender
{
NSLog(#"add to favourites button tapped");
sender.selected = YES;
}
You can use the button state to show a different image. Check the documentation for UIButton, there is a method setImage:forState: that you can use to set an image for normal state, highlighted state, selected state.
You can even do it in Interface Builder.
On a side note, if you want to do something else with the button once it's pressed you should do the following:
Append : to the selector
[_addToFavouritesButton addTarget:_thisController action:#selector(addToFavouritesButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
Receive the UIButton in the method
- (void)addToFavouritesButtonTapped:(UIButton *)sender
Then you can manipulate the button in that method
Is it possible that I can change the background image of some button when I click on another button?
I basically have 10 buttons, and I want the user to know which button is currently clicked. So what happens is each button has 2 images. One for selected and one for not selected.
I want to create a function which will reset the background images of all the buttons. And in the method for each button, I will add this reset function and then change the background image of that specific button.
Can someone suggest how is that possible?
I know how to change the background image of a button when that button is clicked.
This how my buttons look:
- (IBAction)posterButton:(id)sender {}
- (IBAction)colorInvertButton:(id)sender {}
etc..
Look up the documentation for UIButton: configure each button like this:
[button setControlImage:selectedImage forState:UIControlStateSelected];
[button setControlImage:unselectedImage forState:UIControlStateNormal];
^^this can also be done in interface builder btw.
There are also the states UIControlStateNormal | UIControlStateHighlighted and UIControlStateSelected | UIControlStateHighlighted, but this is optional.
A button also has a selected state, inherited from UIControl.
If you want to have only one selected button at a time, try this (_selectedButton should be declared as an instance variable):
- (UIButton *)selectedButton {
return _selectedButton;
}
- (void)setSelectedButton:(UIButton *)b {
if(b != _selectedButton) {
_selectedButton.selected = NO;
b.selected = YES;
_selectedButton = b;
}
}
I have two buttons on my first view,so when I click on one of the button the view changes,so I have two images one for the default state and one for the selected state,
first i tried with xib,goin into the properties and changing the states and then selecting the proper images and when I build and run my code,On cliking the image doesnt change..
So I did this way through code
- (IBAction) handleButton:(id)sender
{
UIButton *button = (UIButton*)sender;
int tag = [button tag];
switch (tag)
{
case BUTTON_1:
if ([m_Button1 isSelected])
{
[m_Button2 setImage:[UIImage imageNamed:#"image.png"] forState:UIControlStateNormal];
[m_Button1 setSelected:NO];
}
else
{
[m_Button1 setImage:[UIImage imageNamed:#"image_pressed.png"] forState:UIControlStateSelected];
[m_Button1 setSelected:YES];
}
[self displaymethod1];
break;
case BUTTON_2:
[self displaymethod2];
break;
default:
break;
}
}
here the image changes when i click on it and i go to diffrent view..when i again come back to my first view,the button is still in selected mode..so How shall i fix this..
Waiting for your reply
I think is a bit simpler through IB.
When you add a regular Round Rect Button in IB you can modify its behavior by going to the Button section in the Attributes Inspector panel.
First select the images you want for it's default state by leaving the State Config in Default. There is an image and a background image properties for this. Once that is set, you can change the State Config to Highlighted and select the image you want to show when the button is highlighted.
NOTE: This is for xcode4.
when your view will appear then you have to initiate all the variable and UI property
in view will appear method. (not necessary in all cases solution is only for your requirement)
There you can set your button default state and image.
-(void)viewWillAppear:(BOOL)animated
{
[m_Button2 setImage:[UIImage imageNamed:#"image.png"] forState:UIControlStateNormal];
[m_Button1 setSelected:NO];
...
}
I have a typical requirement wherein I need to keep a button in highlighted state after pressing it. I need to perform a task which should work only when a button is in highlighted state. Actually I am setting a button state to highlighted programatically.
[sender setHighlighted:YES];
And once the button is in highlighted state i need to perform another action.
- (IBAction)changeState: (UIButton*)sender
{
if (sender.highlighted == YES)
{
[self performSomeAtion:sender];
}
}
But, to my horror, whenever I press any button, the above condition is becoming true and the action is being performed repeatedly. Is there any way in which i can keep a UIButton's state to be highlighted after pressing it?
EDIT - Actually I need to perform 3 different actions for 3 different states of the button. I am already making use of selected state and normal state. Now, I need to make use of the highlighted state.
[sender setSelected:YES];
or you can simulate this effect with two image for your UIButton (notselectedimage.png and selectedimage.png), then keep track button state with a BOOL variable like BOOL buttonCurrentStatus;. Then in .h file:
BOOL buttonCurrentStatus;
and in .m file
// connect this method with Touchupinside function
- (IBAction)changeState:(UIButton*)sender
{
/* if we have multiple buttons, then we can
differentiate them by tag value of button.*/
// But note that you have to set the tag value before use this method.
if([sender tag] == yourButtontag){
if (buttonCurrentStatus == NO)
{
buttonCurrentStatus = YES;
[butt setImage: [UIImage imageNamed:#"selectedImage.png"] forState:UIControlStateNormal];
//[self performSomeAction:sender];
}
else
{
buttonCurrentStatus = NO;
[butt setImage:[UIImage imageNamed:#"notSelectedImage.png"] forState:UIControlStateNormal];
//[self performSomeAction:sender];
}
}
}
- (void)mybutton:(id)sender
{
UIButton *button = (UIButton *)sender;
button.selected = ![button isSelected]; // Important line
if (button.selected)
{
NSLog(#"Selected");
NSLog(#"%i",button.tag);
}
else
{
NSLog(#"Un Selected");
NSLog(#"%i",button.tag);
}
}
The highlighted state is used to highlight the button while it is being touched. A touch down event in the button highlights it. You should use the "selected" state instead.
If what you want to do is perform an action after the button is pressed, don't attach your method to the state change event, attach your method to the TouchUpInside event.
I just find a way, so I share it, just in case...
I kept my UIButton and set one image for each state (so you could go up to a 4 states button).
I set the UserInteractionEnabled to NO -> This button won't receive any touch.
The purpose of this first button is to show a state
I create a second custom UIButton with the same frame than the first one. For this one, none image will be set for the state (it's a fully transparent button). The purpose of this button is to catch the touch event. So I added a target to this button on the TouchUpInside event. And then when the event is fired, I change the state of the first button to Disabled, Highlighted, Selected, or none of these state (= Default state).
Everything is working like a charm!
The way you describe it, you'd be better off subclassing UIView to create your own three-state button.
Actually, you should even implement your own multistate buttonView, and manage the state it's in internally via an array of PNG for the looks and an array of states to know how many times it's been pressed.
Use [sender setSelected: YES];, I think it will be useful to you.
UIButton *btn_tmp=sender;
if(!(btn_tmp.selected))
{
[btn_temp setHighlighted:YES];
}
For iOS 7 only: you should consider setting the image renderMode to UIImageRenderingModeAlwaysTemplate. You can then use the tintColor to represent various states.
see How to apply a tintColor to a UIImage?
and
see Tint a UIView with all its subviews
The solution is tricky but it's possible.
The problem is that you tried to change the highlighted status in the button action method, which I suppose makes a clean up or check process at the end of the action and switch the highlighted status. When you try to debug it you get the highlighted = 1 but it will change at the end.
Strange but your "3 statuses button" is sometimes useful, when you'd like to keep a button in "highlighted" mode like the "selected" mode to get different action depending on the 3 statuses.
The only problem that you couldn't analyze this or switch it to highlighted mode in the button action method as this will switch to highlighted mode immediately as the user push it AND switch it back at the end.
The solution is using a dispatch.
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[theButton setHighlighted:YES];
});
This will do the trick and you could use the 3 statuses.
According to apple, UIButton has a property of imageView:
Although this property is read-only, its own properties are read/write. Use these properties to configure the appearance and behavior of the button’s view
This means that you can set in the IB (in the storyboard) a picture for this button and set the highlighted picture:
Open the Attribute inspector.
Under Button section, choose an image.
In the same section, change the State Config to Highlighted. Notice the image you chose under default is now gone and now you can set a new picture for the Highlighted.
Now you have a button with 2 state config and all you have to do during runtime to change the button.highlighted = true. Also, check the UIControl under Configuring the Control’s Attributes for more states.
You can also do it programatically as follows:
Swift (and almost the same in Objective-C):
// Setting the highlighted image
self.someButton.imageView?.highlightedImage = UIImage(named: "imageNameFromImageAssest")
// someButton will now some the highlighted image and NOT the image set in the IB
self.someButton.imageView?.highlighted = true