保留UITableViewCell选择状态

时间:2014-01-15 00:04:32

标签: ios objective-c cocoa-touch uitableview

为什么UITableViewCell在选择,滚动,然后向后滚动后不重新加载复选标记?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    #define CHECK_NULL_STRING(str) ([str isKindOfClass:[NSNull class]] || !str)?@"":str

    static NSString *CellIdentifier = @"inviteCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    cell.accessoryType = UITableViewCellAccessoryCheckmark;
    cell.textLabel.highlightedTextColor = [UIColor colorWithHexString:@"#669900"];
    cell.selectionStyle = UITableViewCellSelectionStyleGray;
    cell.backgroundColor = [UIColor blackColor];
    cell.textLabel.textColor = [UIColor whiteColor];
    [[UITableViewCell appearance] setTintColor:[UIColor colorWithHexString:@"#669900"]];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] init];
    }

    if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; }

    BOOL isSearching = tableView != self.tableView;
    NSArray *arrayToUse = (isSearching ? searchResults : contactsObjects);
    id p = arrayToUse[indexPath.row];

    NSString *fName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName));
    NSString *lName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName));
    cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", CHECK_NULL_STRING(fName), CHECK_NULL_STRING(lName)];

    BOOL showCheckmark = [[stateArray objectAtIndex:indexPath.row] boolValue];
    if (showCheckmark == YES)
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        NSLog(@"It hit showCheckmark = YES, and stateArray is %@",stateArray[indexPath.row]);
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
        NSLog(@"It hit showCheckmark = NO, and stateArray is %@",stateArray[indexPath.row]);
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
    id object = contactsObjects[indexPath.row];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    if (cell.accessoryType == UITableViewCellAccessoryNone)
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        [stateArray insertObject:[NSNumber numberWithBool:YES] atIndex:indexPath.row];
        [selectedObjects addObject:object];
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [stateArray insertObject:[NSNumber numberWithBool:NO] atIndex:indexPath.row];
        [selectedObjects removeObject:object];
    }

    //slow-motion selection animation.
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

4 个答案:

答案 0 :(得分:2)

您错过了以下行中的!(逆运算符),这意味着状态将始终相同。

[stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:[[stateArray objectAtIndex:indexPath.row] boolValue]]];

应该是

[stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]];

编辑---我重构了这两种方法,因为它可以用很少的代码完成,它将完全简化你的方法。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"inviteCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    BOOL isSearching = tableView != self.tableView;
    NSArray *arrayToUse = (isSearching ? searchResults : contactsObjects);
    id p = arrayToUse[indexPath.row];

    NSString *fName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByFirstName));
    NSString *lName = (__bridge_transfer NSString *)(ABRecordCopyValue((__bridge ABRecordRef)(p), kABPersonSortByLastName));
    cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", CHECK_NULL_STRING(fName), CHECK_NULL_STRING(lName)];

    BOOL showCheckmark = [stateArray[indexPath.row] boolValue];
    if (showCheckmark == YES) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    id object = contactsObjects[indexPath.row];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    if (cell.accessoryType == UITableViewCellAccessoryNone) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        [selectedObjects addObject:object];
    }
    else {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [selectedObjects removeObject:object];
    }
    stateArray[indexPath.row] = @(cell.accessoryType == UITableViewCellAccessoryCheckmark);
}

答案 1 :(得分:1)

我建议采用更面向对象的方法。这将确保您的代码灵活并始终正确显示。

对于您希望在表格中显示的每个项目,都有一个相应的对象。您提到您正在显示联系人,因此我们假设您的对象名为“联系人”:

//Contact.h

@interface Contact : NSObject

@property BOOL selected;
@property NSString *name;

@end

//Contact.m
#import Contact.h
@implementation Contact

+ (id) contactWithName:(NSString*)name {
    Contact *nContact = [Contact new];
    nContact.name = name;
    nContact.selected = NO;
    return nContact;
}
@end

然后,让你的观点像这样:

//ContactView.m

@interface ContactView()

@property NSMutableArray *contacts;

@end

@implementation ContactView
@synthesize contacts;

- (void) viewDidLoad {
    [super viewDidLoad];
    //get your contact list here. When creating contacts, be sure to assign their selected and their name as you require.
    contacts = @[[Contact contactWithName:@"John"], [Contact contactWithName:@"Jane"]];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellID = @"inviteCell";
    UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:cellID];
    if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];

    Contact *cellContact = [contacts objectAtIndex:indexPath.row];
    cell.textLabel.text = cellContact.name;
    cell.accessoryType = cellContact.selected == YES ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    Contact *cellContact = [contacts objectAtIndex:indexPath.row];
    cellContact.selected = !cellContact.selected;
    [contacts replaceObjectAtIndex:indexPath.row withObject:cellContact];
    [tableView reloadData]; //to refresh without animation
    //[tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [tableView numberOfSections])] withRowAnimation:UITableViewRowAnimationTop]; //to refresh with animation
}

@end

繁荣,易于使用的表总是看起来正确,排队正确,并且面向对象以便以后轻松维护。

答案 2 :(得分:0)

即使将insertObject替换为replaceWithObject,单元格选择问题仍未解决,但是,不应该浪费时间设置BOOL内有NSInteger的对象NSMutableArray。相反,对于细胞选择记忆,应该使用NSDictionary,如下所示:

@property (nonatomic, strong) NSMutableDictionary * selectedRowCollection;

- (void)viewDidLoad{

    self.selectedRowCollection = [[NSMutableDictionary alloc] init];
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{    
    id object = contactsObjects[indexPath.row];
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];

    if (cell.accessoryType == UITableViewCellAccessoryNone)
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
        [self.selectedRowCollection setObject:@"1" forKey:[NSString stringWithFormat:@"%d",indexPath.row]]; 
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
        [self.selectedRowCollection removeObjectForKey:[NSString stringWithFormat:@"%d",indexPath.row]];
    }

    //slow-motion selection animation.
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    BOOL showCheckmark =  [[self.selectedRowCollection valueForKey:[NSString stringWithFormat:@"%d",indexPath.row]] boolValue];

    if (showCheckmark == YES)
    {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    }
    else
    {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
}

答案 3 :(得分:-2)

你没有这样做UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:cellID]; if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; } 如果单元格为零,则需要分配。或者在滚动时导致问题。