UITableView在运行时切换不同的自定义单元格

3
我有一个带有两个部分的UITableView,第二个部分包含了一个UISegmentedControl。我想提供一个选项,让用户通过选择UISegmentedControl上的分段来改变tableview的内容。我的TableView还会通过展示不同的自定义单元格更改单元格的外观,这些自定义单元格是我用NIB创建的。我的一个要求是记住表格视图中已加载数据的滚动位置,以便当用户点击我的分段控件来改变表格视图内容并再次点击前一个分段时,我的表格视图能够呈现用户记忆的滚动位置下的数据。
代码:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 2;
}
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    if (section == kUserCoverSection) {
        return 0;
    }
    return 30;
}


-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    if (section == kUserCoverSection) {
        return 1;
    }
    switch (self.userAchievementsType) {
        case kUserSilverCollections:
        {
            return [userSilverArray count];
        }
            break;
        case kUserBronzeCollections:
        {
            return [userBronzeArray count];
        }
            break;
        case kUserGoldsCollections:{
            return [userGoldsArray count];
        }
            break;

        default: return 0;
            break;
    }
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section == kUserCoverSection) {
        return 145;
    }else{
        switch (self.userAchievementsType) {
            case kUserSilverCollections:
            case kUserBronzeCollections:
            {
                return 40;
            }
                break;
            case kUserGoldsCollections:{
                return 358;
            }
                break;
            default:{
                return 40;
            }
                break;
        }
    }


}

-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section {
    if (section == kUserAchievementSection) {
        SegmentControlHeader *sectionHeaderView = [self.mTableView dequeueReusableHeaderFooterViewWithIdentifier:SegmentHeaderViewIdentifier];
        [sectionHeaderView setDelegate:self];
        [sectionHeaderView.segmentControl setSelectedSegmentIndex:self.userAchievementsType];
        return sectionHeaderView;
    }
    return nil;
}
-(UITableViewCell*)tableView:(UITableView*)aTableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
    switch (indexPath.section) {
        case kUserCoverSection:
        {
            static NSString* bannerCellType = @"kCoverBannerCellIdentifier";
            CoverBannerCell *cell = (CoverBannerCell*)[aTableView dequeueReusableCellWithIdentifier:bannerCellType];

            cell.tag = indexPath.row;
            if (cell == nil) {
                NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CoverBannerCell" owner:nil options:nil];
                cell = (CoverBannerCell*)[nib objectAtIndex:0];
            }

            return cell;
        }
        break;

        case kUserAchievementSection:
        {
            switch (self.userAchievementsType) {
                case kUserGoldsCollections:
                { 
                    static NSString* cellType = @"kUserGoldsViewCellIdentifier";
                    UserGoldsViewCell *cell = (UserGoldsViewCell*)[aTableView dequeueReusableCellWithIdentifier:cellType];
                    cell.tag = indexPath.row;
                    if (cell == nil) {
                        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"UserGoldsViewCell" owner:nil options:nil];
                        cell = (UserGoldsViewCell*)[nib objectAtIndex:0];
                    }

                    return cell;
                }
                    break;
                case kUserBronzeCollections:
                case kUserSilverCollections:{
                    static NSString* cellType = @"kUserSilverCellIdentifier";
                    UserSilverCell *cell = (UserSilverCell*)[aTableView dequeueReusableCellWithIdentifier:cellType];
                    cell.tag = indexPath.row;
                    if (cell == nil) {
                        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"UserSilverCell" owner:nil options:nil];
                        cell = (UserSilverCell*)[nib objectAtIndex:0];
                    }
                    return cell;
                }
                break;

                default: { 
                    return [self defaultCell];
                }
                break;
            }

        }
        break;

        default:
            return nil;
            break;
    }

}

-(void)didChangeSegmentValue:(UISegmentedControl *)segment{
    NSInteger index = segment.selectedSegmentIndex;
    NSInteger lastSelectedIndex = self.userAchievementsType;
    switch (lastSelectedIndex) {
        case kUserGoldsCollections: offsetsArray [kUserGoldsCollections] = @(mTableView.contentOffset.y);
            break;
        case kUserSilverCollections: offsetsArray [kUserSilverCollections] = @(mTableView.contentOffset.y);
            break;
        case kUserBronzeCollections: offsetsArray [kUserBronzeCollections] = @(mTableView.contentOffset.y);
            break;
        default:
            break;
    }
    //check if last table scroll header hit top
    if ([offsetsArray[lastSelectedIndex] floatValue] > 144) {
        for (int i = 0; i < [offsetsArray count]; i++) {
            if ([offsetsArray[i] floatValue] < 145 && offsetsArray[lastSelectedIndex] != offsetsArray[i]) {
                offsetsArray[i] = @(145);
            }
        }
    }else{
        for (int i = 0; i < [offsetsArray count]; i++) {
            if ([offsetsArray [i] floatValue] <= 145 && offsetsArray[lastSelectedIndex]!=offsetsArray[i]) {
                CGFloat newOffset;
                newOffset = [offsetsArray[i] floatValue] + ([offsetsArray[lastSelectedIndex] floatValue] -[offsetsArray[i] floatValue] );
                offsetsArray [i] = @(newOffset);
            }else{
                CGFloat newOffset = [offsetsArray[lastSelectedIndex] floatValue];
                offsetsArray [i] = @(newOffset);
            }

        }
    }
    NSRange range = NSMakeRange(1, 1);
    NSIndexSet *section = [NSIndexSet indexSetWithIndexesInRange:range];
    self.userAchievementsType = index;
    [self.mTableView beginUpdates];
    [self.mTableView reloadSections:section withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.mTableView endUpdates];
    [mTableView setContentOffset:CGPointMake(0, [offsetsArray[self.userAchievementsType] floatValue])];

}

我的TableView以正确的数据和正确的滚动位置正确显示。您会在我的代码上注意到,kUserSilverCollectionskUserBronzeCollections 显示相同的自定义单元格,并具有相同的高度,但加载不同的数据源。当用户选择 kUserGoldsCollections(kUserGoldsCollections 比类型 kUserSilverCollectionskUserBronzeCollections 更高)并返回到类型kUserSilverCollectionskUserBronzeCollections时,自定义单元格不再响应触摸,单元格内部的按钮和单元格本身都无法识别触摸,还有一种情况是最后几个单元格可以响应,但其余的不能。
我正在使用iOS 7.1 SDK编写代码。请帮助我找出问题的原因 :) 谢谢!
编辑
我找到了问题的原因,是我的UserGoldsViewCell,现在感觉很傻:D我的问题缺乏细节,比如我的单元格设置。我应该在这个问题中包含我的单元格代码。我将把解决方案/详细信息发布为答案,供未来读者参考。

2
如果您需要帮助解决现有代码的问题,那么您需要发布实际的代码。通过查看虚构的伪代码,没有人能够告诉您代码存在什么问题。 - rmaddy
1
我猜测它出问题是因为你在动画完成之前调整了contentOffset。这种方法似乎过于复杂 - 为什么不只是有三个不同的表视图,并使用分段控件来切换哪一个可见?(它们仍然可以有相同的“delegate”对象。) - Aaron Brager
只是为了明确,您唯一的问题是在从kUserGoldsCollections切换回kUserSilverCollections和kUserBronzeCollections后,单元格不响应触摸吗? - mj_jimenez
@mj_jimenez 没错。 - janusfidel
你覆盖了触摸处理,这可能是问题的根源,因为它与触摸有关。你应该在问题中提到这一点! - Andrea
显示剩余9条评论
2个回答

1
我已经找到了导致这个问题的原因。是我的UserGoldsViewCell重写了hitTest:withEvent方法。以下是我旧的实现方式:
- (UIView *)hitTest:(CGPoint) point withEvent:(UIEvent *)event {
    if ([self pointInside:point withEvent:event]) {
        return scrollView;
    }

    return nil;
}

我重写了这个方法是因为我的 UserGoldsViewCell 里面有一个 UIScrollView,出于 某种原因,我需要重写它。之所以我的 UserSilverCell 在选择 UserGoldsViewCell 后不响应触摸事件,是因为即使呈现的单元格是 UserSilverCell 实例,UserGoldsViewCell 中的 hitTest:withEvent 仍然会被调用并返回其 scrollView。我像下面这样改变了这个方法的实现:
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    UIView* childObj = nil;
    if ((childObj = [super hitTest:point withEvent:event]) == self)
        return self.scrollView;     
    return childObj;
}

1
我不知道为什么你在使用这种Nib的方法:
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"UserSilverCell" owner:nil options:nil];
cell = (UserSilverCell*)[nib objectAtIndex:0];

使用这个,可能会解决你的问题:

在你的 viewDidLoad 中简单地为一个 cellIdenfier 注册你的 nib:

[_yourTableView registerNib:[UINib nibWithNibName:@"UserSilverCell" 
                     bundle:[NSBundle mainBundle]] 
     forCellReuseIdentifier:@"kUserSilverCellIdentifier"];

然后在你的cellForRowAtIndexPath方法中:
UserSilverCell *cell = (UserSilverCell *)[tableView     
            dequeueReusableCellWithIdentifier:@"kUserSilverCellIdentifier" 
                                 forIndexPath:indexPath];

你需要将这个应用到其他类型的单元格上。 这可能是问题,但无论如何,请保持这种方式,因为使用Nib是更好的。

3
很确定这不是问题,但使用现代方法来构建单元格是一个好建议。OP正在使用pre-os6方法,但这并不是问题所在。 - danh
这是我最初创建单元格的方法,但仍然出现了相同的问题 :) 感谢您的建议。 - janusfidel
1
你有其他问题,不是这段代码的问题。另外,有些人不理解投票否定的意义,除非一个答案会对项目或代码产生改进,否则不应该被否定投票。 - Matteo Gobbi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接