Reputation: 9660
I have created a CheckBoxView control for my UITableViewCell. The problem I am facing is that once I checkmark one of the top rows and scrolls the same check mark is visible on the bottom rows. This is because of dequeueresuable rows feature and I want to know how can I fix it. Here is the implementation.
CheckBoxView.m:
-(instancetype) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
[self setup];
[self registerGesturesRecognizers];
return self;
}
-(void) registerGesturesRecognizers {
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(checkBoxTapped:)];
[self addGestureRecognizer:tapGestureRecognizer];
}
-(void) checkBoxTapped:(UITapGestureRecognizer *) recognizer {
if(self.checkBoxViewSelectionChanged) {
if(!self.isChecked) {
self.checkBoxViewSelectionChanged(self,self.isChecked);
self.isChecked = YES;
}
else {
self.checkBoxViewSelectionChanged(self,self.isChecked);
}
}
}
-(void) check {
[_checkBoxImageView setImage:[UIImage imageNamed:@"small-check"]];
}
-(void) uncheck {
_checkBoxImageView.image = nil;
}
-(void) setup {
self.userInteractionEnabled = YES;
self.layer.borderWidth = 0.5f;
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
_checkBoxImageView = [[UIImageView alloc] initWithFrame:CGRectMake(1, 0, 23, 23)];
[self addSubview:_checkBoxImageView];
}
And here is the cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SamplesTableViewCell *cell = (SamplesTableViewCell *) [tableView dequeueReusableCellWithIdentifier:@"SamplesTableViewCell" forIndexPath:indexPath];
Item *sample = [_samples objectAtIndex:[indexPath row]];
cell.productNameLabel.text = sample.product.name;
cell.productColorLabel.text = sample.productColor.name;
[cell.productImageView setImage:sample.productColor.image];
cell.checkboxView.checkBoxViewSelectionChanged = ^(CheckBoxView *checkBoxView, BOOL isChecked) {
if(!isChecked) {
[checkBoxView check];
checkBoxView.isChecked = YES;
}
else {
[checkBoxView uncheck];
checkBoxView.isChecked = NO;
}
};
return cell;
}
The CheckBoxView is actually a UIView on the Storyboard prototype cell whose class is set to CheckBoxView so it is not created dynamically in the cellForRowAtIndexPath event. When I run the above code and checkmark the top rows and scroll then the same checkmark appears on the lower rows.
UPDATE:
Here is my updated code but it still checks and unchecks the rows at the bottom.
cell.checkboxView.checkBoxViewSelectionChanged = ^{
if(!sample.isSelected) {
[sample setSelected:YES];
[cell.checkboxView check];
}
else
{
[sample setSelected:NO];
[cell.checkboxView uncheck];
}
};
Upvotes: 0
Views: 63
Reputation: 9042
Your UIView
should not be maintaining the isChecked
state for your checkbox. As you pointed out, due to cell reuse all the others will then be checked because the same UIView
is being used.
Your model objects powering your data need to maintain the state, or your controller.
For example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SamplesTableViewCell *cell = (SamplesTableViewCell *) [tableView dequeueReusableCellWithIdentifier:@"SamplesTableViewCell" forIndexPath:indexPath];
// Some code...
if ([self.myDatasource[indexPath.row] isChecked]) {
cell.checkBoxView.isChecked = YES;
}
return cell;
}
Just some rough pseudocode, but hopefully you get the idea. Potential ways to implement this state maintained is either in the form of model objects, or in your UIViewController
have an NSArray
containing an NSDictionary
representing each row in your UITableView
, where each key-value pair maintains a particular state for your UITableViewCell
.
Upvotes: 3