奇怪的UITableView行为

时间:2013-03-25 22:26:00

标签: iphone ios objective-c

请看一下图片。 UITable with Cell Displacement

我有一个带有自定义单元格和2个部分的UITableView。一旦UITableView填充了足够的单元格,它们都无法在屏幕上显示,最后一部分中的最后一个单元格将出现在屏幕的最顶部。在UITableView中甚至看不到单元格,因为它是最后一个单元格,并且它完全出现在屏幕顶部的UITableView外面 。我甚至不知道从哪里开始查看我的代码来解决这个问题。我只创建了几个UITableViews,所以我绝对不是这个bug的所有潜在原因的专家。表是通过IB设置的,初始化代码在viewWillAppear中,尽管设置代码不多。我目前正在阅读UITableView的scrollView,以及contentInset,看看是否可能有这种行为的解释。有谁遇到过这样的错误?我觉得它很独特,可能没有必要梳理我的所有代码来确定。无论如何,我将在下面发布相关代码。谢谢你的帮助!

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath     *)indexPath
{

    NSString *uniqueIdentifierForPlayerCell = @"customPlayerCell";

    //Initialize PlayerTableViewCell and set it's properties
    PlayerTableViewCell *playerCell = nil;
    playerCell = (PlayerTableViewCell *)[tableView dequeueReusableCellWithIdentifier:uniqueIdentifierForPlayerCell];

    if (playerCell == nil) {

        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"PlayerTableViewCell" owner:nil options:nil];
        for(id currentObject in topLevelObjects) {
            if([currentObject isKindOfClass:[PlayerTableViewCell class]]) {
                playerCell = (PlayerTableViewCell *)currentObject;
                break;
            }
        }
    }
    playerCell.textLabel.opaque = NO;
    playerCell.textLabel.textColor = self.textColor;
    playerCell.textLabel.font = [UIFont systemFontOfSize:18.0];
    playerCell.textLabel.backgroundColor = [UIColor clearColor];
    playerCell.selectionStyle = UITableViewCellSelectionStyleNone;
    playerCell.accessoryButton.hidden = YES;
    playerCell.reorderButton.hidden = YES;

    NSString *uniqueIdentifierForAlleyCell = @"customAlleyCell";

    //Initialize AlleyTableViewcell and set it's properties
    AlleyTableViewCell *alleyCell = nil;
   alleyCell = (AlleyTableViewCell *)[tableView     dequeueReusableCellWithIdentifier:uniqueIdentifierForAlleyCell];

    if (alleyCell == nil) {

        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"AlleyTableViewCell" owner:nil options:nil];
        for(id currentObject in topLevelObjects) {
            if([currentObject isKindOfClass:[AlleyTableViewCell class]]) {
                alleyCell = (AlleyTableViewCell *)currentObject;
                break;
            }
        }
    }

    alleyCell.textLabel.opaque = NO;
    alleyCell.textLabel.textColor = self.textColor;
    alleyCell.textLabel.font = [UIFont systemFontOfSize:18.0];
    alleyCell.textLabel.backgroundColor = [UIColor clearColor];
    alleyCell.selectionStyle = UITableViewCellSelectionStyleNone;
    alleyCell.accessoryButton.hidden = YES;
    alleyCell.deleteButton.hidden = YES;

//Alternate background colors for each section where section 0 is Alley section and section 1 is Player section. Stores the RGB values of the specific background color to the specific cell for future use
if(indexPath.section == 0 && (indexPath.row %2 == 0)) {
    alleyCell.contentView.backgroundColor = self.backgroundColor;
    alleyCell.isRed = 95.0/255.0;
    alleyCell.isGreen = 94.0/255.0;
    alleyCell.isBlue = 94.0/255.0;
    self.alleyField.backgroundColor = self.backgroundColor;
}
else if(indexPath.section == 0 && (indexPath.row %2 == 1)){
    alleyCell.contentView.backgroundColor = self.alternateColor;
    alleyCell.isRed = 92.0/255.0;
    alleyCell.isGreen = 92.0/255.0;
    alleyCell.isBlue = 92.0/255.0;

    self.alleyField.backgroundColor = self.alternateColor;
}
else if(indexPath.section == 1 && (indexPath.row %2 == 0)) {
    playerCell.contentView.backgroundColor = self.backgroundColor;
    playerCell.isRed = 95.0/255.0;
    playerCell.isGreen = 94.0/255.0;
    playerCell.isBlue = 94.0/255.0;

    self.playerField.backgroundColor = self.backgroundColor;
}
else if(indexPath.section == 1 && (indexPath.row %2 == 1)) {
    playerCell.contentView.backgroundColor = self.alternateColor;
    playerCell.isRed = 92.0/255.0;
    playerCell.isGreen = 92.0/255.0;
    playerCell.isBlue = 92.0/255.0;

    self.playerField.backgroundColor = self.alternateColor;
}

//If Alley array is empty, add alley TextField and return cell
if(indexPath.section == 0) {
    if([self.allAlleys count] == 0) {
        [alleyCell addSubview:self.alleyField];
        self.alleyField.text = nil;
        return alleyCell;
    }
    //Else set the alley name to the nameLabel text and return cell
    else {
        if(indexPath.row < [self.allAlleys count]) {
            alleyCell.textLabel.text = [self.allAlleys objectAtIndex:indexPath.row];
            if([alleyCell.textLabel.text isEqualToString: self.selectedAlley]) {
                alleyCell.accessoryButton.hidden = NO;
            }
            else {
                alleyCell.accessoryButton.hidden = YES;
            }
            return alleyCell;
        }
        //Add alley TextField to the last cell of the UITableView and return cell
        else {
            [alleyCell addSubview:self.alleyField];
            self.alleyField.text = nil;
            return alleyCell;
        }
    }
}
//If Player array is empty, add Player TextField and return cell
else if(indexPath.section == 1) {
    if([self.bowlrNames count] == 0) {
        [playerCell addSubview:self.playerField];
        self.playerField.text = nil;
        return playerCell;
    }
    //Else set the Player name to the nameLabel text and return cell
    else {
        if(indexPath.row < [self.bowlrNames count]) {
            playerCell.textLabel.text = [self.bowlrNames objectAtIndex:indexPath.row];
            for(int i = 0; i < [self.selectedBowlrs count]; i++) {
                if([playerCell.textLabel.text isEqualToString: [self.selectedBowlrs objectAtIndex:i]]) {
                    playerCell.accessoryButton.hidden = NO;
                    playerCell.reorderButton.hidden = NO;
                }
            }
            return playerCell;
        }
        //Add Player textField to the last cell of the UITableView and return cell
        else {
            [playerCell addSubview:self.playerField];
            self.playerField.text = nil;
            return playerCell;
        }
    }
}
}

//Actions for selecting a row in the UITable
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

//If it is in the Alley section
if(indexPath.section == 0) {

    //If the selected cell is the same as the last selected cell
    if(self.lastIndexPathForAlleyCells && indexPath.row == self.lastIndexPathForAlleyCells.row) {
        [tableView beginUpdates];
        self.lastIndexPathForAlleyCells = nil;
        AlleyTableViewCell *previousCell = (AlleyTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
        //[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:YES];
        previousCell.selected = NO;
        self.selectedAlley = nil;
        previousCell.accessoryButton.hidden = YES;
        [tableView endUpdates];
        return;
    }

    //Else the selected cell is not the last selected cell

    AlleyTableViewCell *previousCell = (AlleyTableViewCell *)[tableView cellForRowAtIndexPath:self.lastIndexPathForAlleyCells];
    previousCell.selected = NO;
    previousCell.accessoryButton.hidden = YES;
    AlleyTableViewCell *cell = (AlleyTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
    cell.selected = YES;
    cell.accessoryButton.hidden = NO;
    self.selectedAlley = cell.textLabel.text;

    self.lastIndexPathForAlleyCells = indexPath;
    [self.tableView reloadData];

}

else if(indexPath.section == 1) {
    PlayerTableViewCell *cell = (PlayerTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];

    //If player is not already selected
    if([self playerIsSelected:cell.textLabel.text] == NO) {

        //Set selected to YES and reveal buttons
        cell.selected = YES;
        cell.accessoryButton.hidden = NO;
        cell.reorderButton.hidden = NO;

        //If 8 Players are currently selected, UIAlertView informs user they have reached the limit
        if([self.selectedBowlrs count] == 8) {
            NSString *message = @"You can only select up to 8 players";
            UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"Max Players Selected" message:message delegate:self cancelButtonTitle:[self okButtonTitle] otherButtonTitles:nil, nil];
            alertView.tag = TAG_FULLGAME;
            [alertView show];
        }
        else {
            //Insert name into selectedBowlrs array
            [self.selectedBowlrs insertObject:cell.textLabel.text atIndex:0];

            //Reorder bowlrNames array
            NSString *bowlrName = [self.bowlrNames objectAtIndex:indexPath.row];
            [self.bowlrNames removeObjectAtIndex:indexPath.row];
            [self.bowlrNames insertObject:bowlrName atIndex:0];

            //Move selected row to top of section
            [self moveIndexPathToTop:indexPath];
        }
    }
    //Else the player is already selected
    else {

        //Set selected to NO and hide buttons
        cell.selected = NO;
        cell.accessoryButton.hidden = YES;
        cell.reorderButton.hidden = YES;

        [self.selectedBowlrs removeObject:cell.textLabel.text];
        [self.bowlrNames removeObject:cell.textLabel.text];
        [self.bowlrNames insertObject:cell.textLabel.text atIndex:[self.selectedBowlrs count]];

        [self moveIndexPathToMiddle:indexPath];

        for(int i = 0; i < [self.selectedBowlrs count]; i++) {
            NSLog(@"%@", [self.selectedBowlrs objectAtIndex:i]);
        }
    }
}
[self performSelector:@selector(reloadData) withObject:nil afterDelay:.25];
}

//Returns the number of rows for each section
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
        //For Alley section
    case 0:
        //If the array is empty, return 1 row for the Alley Textfield
        if([self.allAlleys count] == 0)
            return 1;
        //Else return the number of elements in the array + 1 for the Alley Textfield
        else
            return [self.allAlleys count] + 1;
        break;
        //For Player section
    case 1:{
        //If the array is empty, return 1 row for the Player Textfield
        if([self.bowlrNames count] == 0)
            return 1;
        //Else return the number of elements in the array + 1 for the Player Textfield
        else
            return [self.bowlrNames count] + 1;
        break;
    }
    default:
        break;
}
return 0;
}

//Set up appearance for section headers
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0, self.tableView.bounds.size.width, 25.0)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];

CGFloat isRed = 84.0/255.0;
CGFloat isGreen = 84.0/255.0;
CGFloat isBlue = 84.0/255.0;

self.headerColor = [[UIColor alloc]initWithRed:isRed green:isGreen blue:isBlue alpha:0.5];


headerLabel.backgroundColor = self.headerColor;
headerLabel.opaque = NO;
headerLabel.textColor = self.textColor;
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont systemFontOfSize:18.0];
headerLabel.frame = CGRectMake(0.0, 0.0, self.tableView.bounds.size.width, 25.0);

if (section == 0) {
    [headerView setBackgroundColor:self.backgroundColor];
    headerLabel.text = @"Alley";
    [headerView addSubview:headerLabel];
}
else {
    [headerView setBackgroundColor:self.backgroundColor];
    headerLabel.text = @"Bowlr";
    [headerView addSubview:headerLabel];
}
return headerView;
}

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {

return YES;
}

//Used to delete row of UITable
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

self.indexPathForEditing = indexPath;

if(editingStyle == UITableViewCellEditingStyleDelete) {

    //For Alley section
    if(indexPath.section == 0) {

        //Set up UIAlertView
        NSString *message = @"Are you sure?";
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"Delete Alley?" message:message delegate:self cancelButtonTitle:[self cancelButtonTitle] otherButtonTitles:[self deleteButtonTitle], nil];
        alertView.tag = TAG_Alley;
        [alertView show];


    }
    //For Player section
    else if(indexPath.section == 1) {

        //Set up UIAlertView
        NSString *message = @"All information for this Bowlr will be deleted";
        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"Delete Bowlr?" message:message delegate:self cancelButtonTitle:[self cancelButtonTitle] otherButtonTitles:[self deleteButtonTitle], nil];
        alertView.tag = TAG_Player;
        [alertView show];
    }
}
[self performSelector:@selector(reloadData) withObject:nil afterDelay:.25];
}

1 个答案:

答案 0 :(得分:0)

好的,我认为你需要记住两件基本的事情。

(1)您绝不能将某些内容添加到单元格作为子视图。仅将其添加到单元格的contentView。此代码错误:[alleyCell addSubview:self.alleyField];

(2)这些细胞正在重复使用。您可能有100行但只有10个单元格,在用户滚动时不断重复使用。因此,您必须从空状态完全设置每个单元格,如果它不是空状态,则需要将其置于空状态。如果您通过cellForRowAtIndexPath一次向单元格添加文本字段,则必须记住通过cellForRowAtIndexPath删除每个其他行中的文本字段,或者文本字段可以显示在其他行中,因为另一行可能会重复使用同一个细胞。

(另见本书本节末尾的讨论:http://www.apeth.com/iOSBook/ch21.html#_the_three_big_questions它讨论了忘记细胞被重复使用的简单结果。)

另外,我几乎不需要添加框架。你正在添加一个子视图,但我不知道它的框架是什么。使用正确(意味着错误)的帧值,该子视图可能出现在单元格之外。另外,你使用不同高度的细胞吗?如果是这样,请记住,因为细胞正在重复使用,它的高度可能会改变。因此,自动调整行为可能会导致帧发生变化。