NSNoob
NSNoob

Reputation: 5608

How to keep UIButton state selected in UITableView when you have multiple buttons?

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

Answers (5)

NSNoob
NSNoob

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

Vincent Bernier
Vincent Bernier

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

Rog
Rog

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

Viper
Viper

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

freshking
freshking

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

Related Questions