Reputation: 5608
I have a table View containing buttons. What I want to do is, I want to keep tapped button(s) in selected state until they are tapped again (That's supposed to deselect them). It's like a Check Box to be honest. Simple, Right?
But the problem is, because of using single boolean flag to see whether button is pressed for the first time or second time, Things get messy. e.g. i click button one, then i click button two, now I want to deselect button one so I click it again but it doesn't deselect because Flag is set to YES (Though it does deselect on clicking once again).
Is there a way to avoid this and achieve the desired result in just one click? screenshot: http://i60.tinypic.com/1z51653.png This is what I'm doing:
-(void) btnStateChanged: (UIButton *) btnProblem
{
static BOOL btnPressedFirstTime=YES;
if(btnProblem.selected==YES || btnProblem.highlighted==YES)
{
if(btnPressedFirstTime==YES)
{
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button_hover"] forState: UIControlStateNormal];
btnPressedFirstTime=NO;
}
else if(btnPressedFirstTime==NO)
{
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button"] forState: UIControlStateNormal];
btnPressedFirstTime=YES;
}
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
Upvotes: 1
Views: 1164
Reputation: 5608
Thanks for the responses guys. I tried few of your answers but idk maybe because I didn't understand that right, it didn't work for me. This is what I figured out and it works fine for the given problem. I should have thought of it before, so silly of me. TAGS! That was what i needed.
-(void) btnStateChanged: (UIButton *) btnProblem
{
if (btnProblem.tag == 1000) {
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button_hover"] forState: UIControlStateNormal];
btnProblem.tag = 1001;
}else if(btnProblem.tag == 1001) {
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button"] forState: UIControlStateNormal];
btnProblem.tag = 1000;
}
Upvotes: 0
Reputation: 8664
Why not just subclass UIButton to have the visual behaviour that you want?
After all, a button is something that is already tracking its state.
@interface CBBCheckBoxLikeButton : UIButton
@end
@implementation CBBCheckBoxLikeButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
[self communInit];
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
[self communInit];
return self;
}
- (void)communInit
{
// The image setting could be done from the outside ot the class
[self setBackgroundImage:[[UIImage imageNamed:@"grayPixel"] resizableImageWithCapInsets:UIEdgeInsetsZero] forState:UIControlStateNormal];
[self setBackgroundImage:[[UIImage imageNamed:@"greenPixel"] resizableImageWithCapInsets:UIEdgeInsetsZero] forState:UIControlStateSelected];
self.selected = NO;
}
- (void)setHighlighted:(BOOL)highlighted
{
[self updateSelectedStateForHighlighted:highlighted];
[super setHighlighted:highlighted];
}
- (void)updateSelectedStateForHighlighted:(BOOL)highlighted
{
if (highlighted)
self.selected = !self.selected;
}
@end
But you will still have the problem of dealing with the TableView Reuse Mechanism to keep your visual in sync with your button. But that is probably reflected in your data model.
So in your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
method you will only need to do :
cell.button.selected = dataForCell.wasButtonSelected;
Note that the button will need to be a 'custom' button, 'system' button will behave strangely. You could/should provide a creation method that would avoid that client code pitfall.
Upvotes: 0
Reputation: 17170
This is exactly what NSMutableIndexSet
is for. It's effectively a sparse array of bool flags.
You can set or unset any flag by calling addIndex:
to set and removeIndex:
to unset. You test the value of one of those flags using NSIndexSet
's containsIndex:
.
The code would look a lot like @freshking's NSMutableArray code but you'll have a lot less boolValue and numberWithBool: faffing.
Upvotes: 0
Reputation: 1408
Use a array to store objects of selected or you can say tapped buttons... and in the function called on tap check if that button is in array or not.. and change image accordingly e.g.-
NSMutableArray *selectedBtnArr = [[NSMutableArray alloc]init];
if ([selectedBtnArr containsObject:btnProblem]) {
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button"] forState: UIControlStateNormal];
[selectedBtnArr removeObject:btnProblem];
}else{
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button_hover"] forState: UIControlStateNormal];
[selectedBtnArr addObject:btnProblem];
}
Or if you don't want to use array for the task than use tag.. set button tags like 1,2,3..10 I assume you have 10 buttons. and use this code to identify if button is selected or not -
if (btnProblem.tag < 100) {
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button_hover"] forState: UIControlStateNormal];
btnProblem.tag = btnProblem.tag+100;
}else{
[btnProblem setBackgroundImage:[UIImage imageNamed:@"sc123_button"] forState: UIControlStateNormal];
btnProblem.tag = btnProblem.tag-100;
}
Upvotes: 0
Reputation: 1864
Initiate an array with objects describing the state for each button. So lets say you have 10 buttons:
NSMutableArray *buttonStates = [NSMutableArray new];
for (int i = 0; i < 10; i++)
{
[buttonStates addObject:[NSNumber numberWithBool:NO]];
}
Now when you click button number 2 (be aware that you must tag the button with the index of its row):
- (void)btnStateChanged:(UIButton *)btnProblem
{
int buttonIndex = btnProblem.tag;
BOOL state = [[buttonStates objectAtIndex:buttonIndex] boolValue];
[buttonStates replaceObjectAtIndex:buttonIndex withObject:[NSNumber numberWithBool:!state]];
}
That way you always know which state each button has.
Upvotes: 1