質問

I have a UITableView,with two sections, the second section contains a UISegmentedControl in its header. I want an option for the user to change the tableview content by selecting a segment in my UISegmentedControl. My TableView also changes the cells appearance by presenting different customcells I created with NIBs. One of my requirements is to remember the scroll position of my table view for loaded data in my tableview, so that when the user taps on my segment control to change tableview content and taps again the previous segment, my tableview will be able to present the data with the scroll position that the user remembers.

Code:

-(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])];

}

My TableView displays properly with correct data and correct scroll positions. You would notice on my code that kUserSilverCollections and kUserBronzeCollections displays the same custom cell,and has the same height, but loads different data source.I am having this problem when the user selects kUserGoldsCollections (kUserGoldsCollections has bigger height than types kUserSilverCollections & kUserBronzeCollections) , and go back to type kUserSilverCollections or kUserBronzeCollections, the custom cells are not responding to touches anymore,buttons inside cell and the cell itself do not recognize touches, there is also a case that last few cells are responding. but the rest are not.

Im writing the code in iOS 7.1 SDK. Please help me find out what causes this problem :) Thank you!

EDIT

I found out what causes the problem, it was my UserGoldsViewCell now i feel stupid :D My question is lack of details like my cell setup. I should have included my code for my cells in this question.I Will post the solution/details as answer for future readers.

役に立ちましたか?

解決 2

I have found what causes this problem. It was my UserGoldsViewCell that overrides hitTest:withEvent method. Below was my old implementation of the method:

- (UIView *)hitTest:(CGPoint) point withEvent:(UIEvent *)event {
    if ([self pointInside:point withEvent:event]) {
        return scrollView;
    }

    return nil;
}

I override this method because my UserGoldsViewCell has a UISrollView in it and for a reason, I need to override it. The reason why my UserSilverCell does not respond to touch event after selecting UserGoldsViewCellis because even the presented cells are UserSilverCell instance, the hitTest:withEvent in my UserGoldsViewCell still gets called and returning its' scrollView. I change my implementation for this method like below:

-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    UIView* childObj = nil;
    if ((childObj = [super hitTest:point withEvent:event]) == self)
        return self.scrollView;     
    return childObj;
}

他のヒント

I don't know why you are using this methodology for Nib:

NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"UserSilverCell" owner:nil options:nil];
cell = (UserSilverCell*)[nib objectAtIndex:0];

Use this, could be your problem:

In your viewDidLoad simply register your nib for a cellIdenfier:

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

and then in your cellForRowAtIndexPath:

UserSilverCell *cell = (UserSilverCell *)[tableView     
            dequeueReusableCellWithIdentifier:@"kUserSilverCellIdentifier" 
                                 forIndexPath:indexPath];

You have to apply this also to the other your type of cell.

This could be the problem, but if it isn't in any case maintain this way because is the better with Nib.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top