I have a UIButton with an image inside of a UITableViewCell. When the cell is being highlight, the button is also entering the highlighted state (i.e. a darker shade of the image), regardless of whether the user is clicking within the bounds of the button or not.
I don't want this functionality - I only want the button to be highlighted when the button is clicked, not when the entire cell is being clicked.
I've tried to set the image in the highlighted state to be the same as the normal image. This fixes the issue however it stops the button from changing color when it really is highlighted.
Any ideas how to achieve the desired effect?
This was driving me crazy. I figured out that you need to override setHighlighted:animated: and setSelected:animated:
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[super setHighlighted:highlighted animated:animated];
self.yourButton.highlighted = NO;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.yourButton.selected = NO;
// If you don't set highlighted to NO in this method,
// for some reason it'll be highlighed while the
// table cell selection animates out
self.yourButton.highlighted = NO;
}
One approach would be to "deselect" or "unhighlight" the button when the table view cell is selected:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[yourButton setHighlighted:NO];
// do something cool
}
codecaffeine's suggestion didn't work for me (iOS 8.3), but it did put me on the right track. I modified it like this (it's in Swift though):
override func setHighlighted(highlighted: Bool, animated: Bool) {
var colorBefore = self.myButton.backgroundColor
super.setHighlighted(highlighted, animated: animated)
self.myButton.highlighted = false
self.myButton.backgroundColor = colorBefore
}
I've used a different approach, it's a little bit easier, I hope it works for you. Just set the button's highlighted state to false inside the two above delegate methods:
-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *btnAction = (UIButton *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:3];
btnAction.highlighted = NO;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIButton *btnAction = (UIButton *) [[tableView cellForRowAtIndexPath:indexPath] viewWithTag:3];
btnAction.highlighted = NO;
}
Haven't actually tried this, but could you maybe add a target / action to the button for UIControlEventTouchDown that updated its highlighted-state image to what you wanted, then another target / action for UIControlEventTouchUpInside / UIControlEventTouchUpOutside / UIControlEventTouchCancel that reset the highlighted image to match the normal-state image?
A possible workaround would be that, you set the cell selection style to be none. In that case when you select the cell, it would not be highlighted.
This is only, the possible workaround. May be you have other things in your mind.
To make it work, I had to use the following subclassing on the UITableViewCell. The 'button' object is the button inside the custom cell:
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
[self.button setShowsTouchWhenHighlighted:NO];
[super setHighlighted:highlighted animated:animated];
self.button.highlighted = NO;
[self.button setShowsTouchWhenHighlighted:YES];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[self.button setShowsTouchWhenHighlighted:NO];
[super setSelected:selected animated:animated];
self.button.highlighted = NO;
// Configure the view for the selected state
[self.button setShowsTouchWhenHighlighted:YES];
}
Interverting the various line may result in the highlighting of the button.
Related
I have a custom UITableViewCell. I've got a UIImageView on top of a UIButton. Now when I click the UIButton, I'm able to toggle the image of the UIImageView something similar to a radio button.
The problem is, when I toggle it to the state 'YES', there is a call to the server that makes the required change. Now when I reload the table, the UIImageView doesnt change to the 'YES' state. I set the UIButton state to 'Selected' and that's working fine. But the UIImageView doesnt change to the new image.
On update I get this:
When I actually want this:
The default state is this:
The updated state and the default state of the UIImageView is the same.
Here the round icon is the UIImageView and the rest is a UIButton
This is what I've been trying to do:
In the custom UITableViewCell:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
self.karmaLogo = [[UIImageView alloc] initWithFrame:CGRectMake(self.karmaButton.frame.size.width - 40, 8, 30, 30)];
[self.karmaLogo setImage:[UIImage imageNamed:#"logo-grey"]];
self.karmaLogo.userInteractionEnabled = NO;
[self.karmaButton addSubview:self.karmaLogo];
}
And in the UITableView delegate:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Creates the required custom cell
if (karmaCheck == 1) // Received from the server
{
cell.karmaButton.highlighted = YES;
cell.karmaButton.selected = YES;
cell.karmaLogo.image = nil;
[cell.karmaLogo setImage:[UIImage imageNamed:#"logo-black"]];
[cell.karmaLogo setNeedsDisplay];
[cell bringSubviewToFront:cell.karmaLogo];
}
else
{
cell.karmaButton.highlighted = NO;
cell.karmaButton.selected = NO;
cell.karmaLogo.image = nil;
[cell.karmaLogo setImage:[UIImage imageNamed:#"logo-grey"]];
[cell.karmaLogo setNeedsDisplay];
[cell bringSubviewToFront:cell.karmaLogo];
}
The execution does enter both the if and the else block as and when required but doesnt change the image. But the highlighting and the selection of the karmaButton (UIButton) works fine.
As per you statement "when I reload the table, the UIImageView doesnt change to the 'YES' state."
This is because whenever you reload the Table your - (void)setSelected:(BOOL)selected animated:(BOOL)animated gets called in which you are explicitly setting the image in ImageView using [self.karmaLogo setImage:[UIImage imageNamed:#"logo-grey"]];
So do your conditional checking in - (void)setSelected:(BOOL)selected animated:(BOOL)animated instead of cellForRowAtIndexPath:(NSIndexPath *)indexPath
You're adding the image as a subview of the button, so the image is getting highlighted when you highlight the button. The reason you're seeing a problem, I think, is due to a bug in UIImageView when you don't explicitly set the highlighted image. So, rather than toggling the image, try doing this outside of your if-else block:
[cell.karmaLogo setImage:[UIImage imageNamed:#"logo-grey"]];
[cell.karmaLogo setHighlightedImage:[UIImage imageNamed:#"logo-black"]];
I am having UITableView with customCell(CustomCell having 2 lables and One ImageView).
In normal Mode I need white color of all the cells.
If user press the particular cell, then color of that cell should be gray(rest of the cells should be white)
And If user release the same cell, Color of that cell should be Orange(rest of the cells should be white)
How can I figure it out?
I have tried this using setSelectedBackground, willSelectRowAtIndexPath and Gestures methods. But can't see these 3 Color states for the same Cell. Any Of the 2 states are working together.
Any Idea how can i achieve the same functionality?
I have implemented same functionality in android using selectors. I want the same functionality in iPhone. Any Help?
Thanks in advance!
Write these two method in your Custom Cell
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
self.contentView.backgroundColor=[UIColor greenColor];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
self.contentView.backgroundColor=[UIColor orangeColor];
}
A pretty elegant solution is to override the setHighlighted: method of your tableViewCells.
- (void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
if(highlighted) {
_backView.backgroundColor = [UIColor blueColor];
}
else
{
_backView.backgroundColor = [UIColor blackColor];
}
}
UITableView will automatically set the selected cell highlighted #property to YES when the user tap on the cell.
Don't forget to call [_tableView deselectCellAtIndexPath:indexPath animated:NO]; in your didSelect tableView delegate method if you want to make your cell unselected!
If you want gray then
cell.selectionStyle=UITableViewCellSelectionStyleGray;
Or you can set background color on didSelectRow
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView reloadData];
UITableViewCell *cell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[cell setBackgroundColor:[UIColor orangeColor]];
}
If you don't want to reload tableData then you have to save your previousSelected Index value then
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Make oreange cell
UITableViewCell *presentCell=(UITableViewCell*)[tableView cellForRowAtIndexPath:indexPath];
[presentCell setBackgroundColor:[UIColor orangeColor]];
//make your previous cellBackgrod to clear, you can make it white as per your requirement
UITableViewCell *previouscell=(UITableViewCell*)[tableView cellForRowAtIndexPath:previousSelectedCellIndexPath];
[previouscell setBackgroundColor:[UIColor clearColor]];
//save your selected cell index
previousSelectedCellIndexPath=indexPath;
}
I am trying to create a UITableView with a custom UIButton in each table cell. I implemented like this..
#implementation CouponDetailsCustomTableViewCell
...............
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
[self setBackgroundColor:[UIColor whiteColor]];
CGRect frame = self.contentView.frame;
self.radioButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.radioButton setImage:[UIImage imageNamed:#"radio_blank.png"] forState:UIControlStateNormal];
[self.radioButton setImage:[UIImage imageNamed:#"radio_selected"] forState:UIControlStateSelected];
[self.radioButton setFrame:CGRectMake(16, 10, 29, 29)];
[self.radioButton addTarget:nil action:#selector(radioButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:radioButton];
}
#end
and UITableView Delegate as......
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *COUPON_CELL_ID = #"CouponCell" ;
CouponDetailsCustomTableViewCell * couponCell = (CouponDetailsCustomTableViewCell *) [tableView dequeueReusableCellWithIdentifier:COUPON_CELL_ID];
if (couponCell == nil) {
couponCell = [[[CouponDetailsCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:COUPON_CELL_ID] autorelease];
couponCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
[couponCell.radioButton setSelected:NO];
return couponCell;
}
and the radioButtonPressed method is
-(void)radioButtonPressed:(id) sender
{
[sender setSelected:YES];
}
Now i run the program and a custom UIButton is shown in every table row . If i click on a button it gets selected (shows the radio_selected.png).
The problem arises when i scroll down the table (i am showing only 4 rows of the table in the window) . When i scroll up again..what i see is the clicked button is showing the radio_blank.png.
I am new in iPhone development. i dont know why is this happening. The most i can guess is the button property is changing .. setSelected:NO.
Someone please give me suggestions to fix this problem.
Thank you.
When you scroll your UITableView, hidden cells are not rendered anymore and might be reused for cells that are becoming visible. If a new cell becomes visible, tableView:cellForRowAtIndexPath: gets called.
The problem is that you're setting the selected state there:
[couponCell.radioButton setSelected:NO];
Therefore, whenever you scroll your cell out of the visible area and back again, it gets reset to selected = NO.
I suggest you create a NSMutableDictionary where you store the selection state of each row/NSIndexPath, which you then re-apply in tableView:cellForRowAtIndexPath:.
replace [couponCell.radioButton setSelected:NO]; in tableView:cellForRowAtIndexPath: with code that sets the selected property depending on a state from your dataSource.
something along those lines:
/* get the button state from your data source */
FancyCouponObject *coupon = [self.coupons objectAtIndex:indexPath.row];
BOOL buttonState = coupon.buttonState;
[couponCell.radioButton setSelected:buttonState];
The cells of a tableView are reused when they are moved off screen. You can't save state in them.
problem is when you scroll the table at that time your cellForRowAtIndexPath: delegate method called for every row... so here when its called at time your setSelected Method call with NO argument like bellow...
[couponCell.radioButton setSelected:NO];
so when you scroll table at time your setSelected method call and your button turn with radio_blank.png
...
:)
-(void)radioButtonPressed:(id) sender
{
[sender setSelected:YES];
}
in this method you are setting button as selected and for selected button you have set the radio_blank.png image
I can not set the custom cells accessory view while the page loads for the first time, any ideas?
In DetailView customcell's class I have this:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if(self.selected)
self.accessoryType=UITableViewCellAccessoryCheckmark;
else
self.accessoryType=UITableViewCellAccessoryNone;
}
And In tableview controller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewCell *cell = [DetailViewCell cellForTableView:tableView];
if(somelogichere){
[cell setSelected:YES];
}
return cell;
}
I debug and hit that line so logic is true, but in debug I also see that after it sets the accesory then again it calls twice the selected method, which overrrides the accessory to none in the else inthe second call. setSelected causes the selected method to be called twice and overrides the setting on the second call cause somehow on second call self.selected returns false;
UPDATE: I solved the problem by creating a boolean cellSelected property in the custom cell class and changing and checking its status rather than setting and changing the selected property of the cell, this is also better cause I can support multi selection tableview's better in future.
Does it work the second time after the view has loaded?
It most probably has something to do with following line:
if(somelogichere){
[cell setSelected:YES];
}
What is somelogichere ?
Depending on somelogichere your selected property might not be true the first time you run your code:
if(self.selected)
self.accessoryType=UITableViewCellAccessoryCheckmark;
else
self.accessoryType=UITableViewCellAccessoryNone;
Make sure you set your cell's selected property in the beginning. Or change the code inside your setSelected.
HTH
You try this code its help u
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
UIImage *selectionBackground = [UIImage imageNamed:#"list_BG.jpg"];
UIImageView *iview=[[UIImageView alloc] initWithImage:selectionBackground];
self.selectedBackgroundView=iview;
}
OR
In cellForRowAtIndexPath method of tableView:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
I'm trying to use a UITableViewController and replace the editing mode button (usual default is 'Delete') with a custom view.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... (other code) ...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.tag = pd.itemId;
UIImage *indicatorImage = [UIImage imageNamed:#"indicator.png"];
cell.editingAccessoryView = [[[UIImageView alloc] initWithImage:indicatorImage] autorelease];
//cell.accessoryView = [[[UIImageView alloc] initWithImage:indicatorImage] autorelease];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
When I try to swipe, nothing happens. What's strange is that if I uncomment the cell.accessoryView line, my image appears fine. This makes me think that it something about the editing settings that is wrong? But nowhere online or in documentation can I find what those settings are supposed to be.
Thanks!
Update: Ah. okay, so I gave myself an 'edit' button for the UITableView nav controller. Now I can toggle all the cells into edit mode, and my accessory appears. What does 'swiping' a cell do then?
Kurt
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
canEditRowAtIndexPath should return YES if you set the editingAccessoryView and want it to appear. Plain accessoryView is visible while the table is not in editing mode. However the swiping of the cell shows the delete confirmation button which isn't the editingAccessoryView, and messing with
- (void)willTransitionToState:(UITableViewCellStateMask)state;
without calling [super willTransitionToState:state]; will lead to unexpected behavior (your cell will not leave the UITableViewCellStateShowingDeleteConfirmationMask state). If you can manage calling super and not allowing the cell to show the delete confirmation button, then you're done.