【问题标题】:How can I update/reload/refresh a section header view in a UITableView?如何更新/重新加载/刷新 UITableView 中的节标题视图?
【发布时间】:2012-08-07 01:14:06
【问题描述】:

我愿意在单击一行时更改 UITableView 的特定标题视图。

我已经阅读了所有个关于它的帖子。我尝试了“reloadData”、“setNeedDisplay”、“reloadSections:withRowAnimation:”和其他几个想法……没有什么可做的。我的标题视图要么不更新,要么只在我移动表格视图时才更新(这不是我愿意实现的)。

我的代码现在看起来像这样(关于 UITableView 委托方法):

-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
    if(tableView==_storeTableView){
        return [_storeDataArray count];
    } else {
        return 1;
    }
}

-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section {
    if(tableView==_storeTableView){
        HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:section];
        if (!headerModel.headerView) {
            NSString *shelfName = headerModel.shelf;
            headerModel.headerView = [[[HouraStoreHeaderView alloc] initWithFrame:CGRectMake(0.0, 0.0, _storeTableView.bounds.size.width, 80) title:shelfName section:section subheaderNumber:([headerModel.openedSubHeaders count]-1) delegate:self] autorelease];
        }
        return headerModel.headerView;
    } else {
        return nil;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if(tableView==_storeTableView){
        HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:section];
        NSDictionary *myDict = _storeDataDict;
        for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
            myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
        }
        NSInteger numberOfRowsInSection = [[myDict allKeys] count];
        return headerModel.open ? numberOfRowsInSection : 0;
    } else if(tableView==_searchTableView){
        return [_resultArray count];
    } else {
        return 0;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    if(tableView==_storeTableView){
        HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
        NSDictionary *myDict = _storeDataDict;
        for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
            myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
        }
        cell.accessoryView=[[[HouraStoreCellView alloc] initWithFrame:CGRectMake(0.0, 0.0, _storeTableView.bounds.size.width, 50) title:[[myDict allKeys] objectAtIndex:indexPath.row]] autorelease];
        return cell;
    } else if (tableView==_searchTableView) {
        cell.textLabel.text = [_resultArray objectAtIndex:indexPath.row];
        return cell;
    } else {
        return cell;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:section];
    NSInteger height = 59.0 + ([headerModel.openedSubHeaders count]-1)*41.0;
    return height;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    if(tableView==_storeTableView){
        HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
        NSDictionary *myDict = _storeDataDict;
        for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
            myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
        }
        if ([[myDict objectForKey:[[myDict allKeys] objectAtIndex:indexPath.row]] isKindOfClass:[NSDictionary class]]) {
            [self cellOpened:indexPath];
        } else {
            [_activityIndicatorView startAnimating];
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(_listProductsFoundedFinished:)
                                                         name:HouraSearchProductsDone
                                                       object:nil]; 
            NSString *searchString = [[myDict allKeys] objectAtIndex:indexPath.row];
            searchString = [searchString stringByReplacingOccurrencesOfString:@"\"" withString:@"\\u0022"];
            [_singleton.util beginSearchProducts:searchString context:@"2"];
        }
    } else if(tableView==_searchTableView){
        _searchBar.text = [_resultArray objectAtIndex:indexPath.row];

        [_searchBar resignFirstResponder];
        [_activityIndicatorView startAnimating];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(_listProductsFoundedFinished:)
                                                     name:HouraSearchProductsDone
                                                   object:nil]; 
        [_singleton.util beginSearchProducts:_searchBar.text context:@"2"];
    }
}

-(void)headerView:(HouraStoreHeaderView*)headerView headerOpened:(NSInteger)headerOpened {
    if (self.openSectionIndex!=NSNotFound) {
        [self closeAllHeaders];
    }
        //[self closeAllHeaders];
    HouraStoreHeaderModel *headerModel =nil;

    headerModel = [self.headerInfoArray objectAtIndex:headerOpened];
    headerModel.open = YES;
    headerModel.headerView.disclosureButton.selected = YES;

    NSDictionary *myDict = _storeDataDict;
    for (NSInteger i = 0; i < [headerModel.openedSubHeaders count]; i++) {
        myDict = [myDict objectForKey:[headerModel.openedSubHeaders objectAtIndex:i]];
    }
    NSInteger countOfRowsToInsert = [[myDict allKeys] count];

    NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
    for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
        [indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:headerOpened]];
    }

    NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];

    NSInteger previousOpenSectionIndex = self.openSectionIndex;
    if (previousOpenSectionIndex != NSNotFound) {

        HouraStoreHeaderModel *previousHeaderModel = [self.headerInfoArray objectAtIndex:previousOpenSectionIndex];
        previousHeaderModel.open = NO;
        previousHeaderModel.headerView.disclosureButton.selected = NO;
        [previousHeaderModel.headerView toggleOpenWithUserAction:NO];
        NSInteger countOfRowsToDelete = [[[_storeDataDict objectForKey:previousHeaderModel.shelf ] allKeys] count];
        for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
            [indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
        }
    }
    UITableViewRowAnimation insertAnimation;
    UITableViewRowAnimation deleteAnimation;
    if (previousOpenSectionIndex == NSNotFound || headerOpened < previousOpenSectionIndex) {
        insertAnimation = UITableViewRowAnimationTop;   
        deleteAnimation = UITableViewRowAnimationBottom;
    } else {
        insertAnimation = UITableViewRowAnimationBottom;
        deleteAnimation = UITableViewRowAnimationTop;
    }

    [_storeTableView beginUpdates];
    [_storeTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
    [_storeTableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:insertAnimation];
    [_storeTableView endUpdates];

    self.openSectionIndex = headerOpened;
}

-(void)headerView:(HouraStoreHeaderView*)headerView headerClosed:(NSInteger)headerClosed {

    HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:headerClosed];

    headerModel.open = NO;
    headerModel.headerView.disclosureButton.selected = NO;
    [headerModel cleanOpenedSubHeaders];
    [self.headerInfoArray replaceObjectAtIndex:headerClosed withObject:headerModel];

    NSInteger countOfRowsToDelete = [_storeTableView numberOfRowsInSection:headerClosed];

    if (countOfRowsToDelete > 0) {
        NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
        for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
            [indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:headerClosed]];
        }
        [_storeTableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
    }
    self.openSectionIndex = NSNotFound;
}

-(void)cellOpened:(NSIndexPath*)indexPath {
    HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
    [self headerView:headerModel.headerView headerClosed:indexPath.section];
    [headerModel addOpenedSubHeaders:[[[_storeDataDict objectForKey:headerModel.shelf] allKeys] objectAtIndex:indexPath.row]];
    [self.headerInfoArray replaceObjectAtIndex:indexPath.section withObject:headerModel];
    headerModel = [self.headerInfoArray objectAtIndex:indexPath.section];
    [self headerView:headerModel.headerView headerOpened:indexPath.section];
}

-(void)closeAllHeaders {
    for (NSInteger i = 0; i < [self.headerInfoArray count]; i++) {
        HouraStoreHeaderModel *headerModel = [self.headerInfoArray objectAtIndex:i];
        [self headerView:headerModel.headerView headerClosed:i];
    }
}

我想做的是,当我单击一行时,部分标题会更新,因此它包含一个带有行文本的新按钮。然后我关闭该行并在部分行中重新加载新数据。我设法完美地处理了这些行。但我找不到更新此标题视图的方法。

感谢任何想法。

【问题讨论】:

  • 你试过 reloadSections:withRowAnimation: 吗?
  • 是的,正如我所提到的,我已经尝试过这个和“reloadData”/“setNeedsDisplay”。

标签: uitableview header


【解决方案1】:

您是否尝试过reloadRowsAtIndexPaths:withRowAnimation:,将NSIndexPath 的row 属性设置为NSNotFound?因此,仅重新加载第 3 节的标题,例如看起来像

NSIndexPath * headerIndexPath = [NSIndexPath indexPathForRow: NSNotFound section:3];
[self.tableView reloadRowsAtIndexPaths:@[headerIndexPath] withRowAnimation: UITableViewRowAnimationAutomatic];

我什么都不保证,但我很确定它以前可以工作,因为我用过几次。

但即使它有效,它仍然是一个可能随时被 Apple 破解的 hack。

编辑

好吧,没关系。我在 Xcode 5 中使用 iOS 7 进行了尝试,出于某种原因,即使将 NSNotFound 作为行号,它仍然会重新加载整个部分(及其所有单元格)。所以这不再起作用了,该死的。

【讨论】:

    【解决方案2】:

    您只需直接更改它。我在头文件中为一个标签创建了一个实例变量,我将把它放在我将创建的头视图中:

    @interface MainViewController : UITableViewController {
        // creating my datasource array instance variable
        NSArray *_items;
    
        // this is the label I will add to the header view when I create it
        UILabel *_headerLabel;
    }
    
    @end
    

    在我的 tableView 中,当他们选择一行时,我会调用一个函数来简单地更改标签上的文本:

    @implementation MainViewController
    
    - (id)init {
        self = [super initWithStyle:UITableViewStyleGrouped];
    
        / filling my datasource with test strings
        _items = @[@"one", @"two"];
    
        return self;
    }
    
    - (void)changeHeaderLabel:(NSString *)newLabel {
        // when this function gets called and is passed a string, I will simply
        // set the text on the label to the new string and viola!
        _headerLabel.text = newLabel;
    }
    
    #pragma mark - Table view data source
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        // this table will only have a single section for demo purposes
        return 1;
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        // return the count of my datasource array
        return _items.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        // attempt to create a cell by reusing one with a given identifier
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    
        // if I wasn't able to reuse one
        if (cell == nil) {
            // create one from scratch with that identifier
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        }
    
        // now simply set the text on the cell from my data source array of strings
        cell.textLabel.text = _items[indexPath.row];
    
        // and return the cell
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // deselect the row so the cell automatically fades out after selection
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
        // here you could do one of two things, either get a reference to the cell itself,
        // and then get the value stored in it's textLabel
        UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
        NSString *newHeaderTitleString = selectedCell.textLabel.text;
    
        // OR you can get it right from your datasource
        NSString *newHeaderTitleString = _items[indexPath.row];
    
        // then just call the above function with the string as the single param
        [self changeHeaderLabel:newHeaderTitleString];
    }
    
    - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
        // here I just create a view that will span the whole frame and is an arbitrary height
        UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 80)];
        // set the background color to clear
        headerView.backgroundColor = [UIColor clearColor];
    
        // then I initialize my instance variable with a frame that's centered in the view
        // for aesthetic purposes
        _headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.view.frame.size.width - 10, 80)];
    
        // then I set the text color, add an autoresizing mask so if the view rotates
        // it still remains centered properly, set the text to some starting value, 
        // and add it to the headerView I previously created
        _headerLabel.textColor = [UIColor darkGrayColor];
        _headerLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        _headerLabel.text = @"Before";
        [headerView addSubview:_headerLabel];
    
        // then I return the headerView
        return headerView;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
        // return an arbitrary height here for testing
        return 80;
    }
    

    结果如下:

    如果您有任何问题,请告诉我!这只是一个演示它的快速示例,但您可能希望以完全不同的方式自定义视图。这至少应该可以解决您的问题,并为您提供工作的起点。

    【讨论】:

    • 问题来的不仅仅是改变,比如 subvies 等。不仅如此,还要改变高度。
    • 举个例子,我用来改变视图的每一次尝试都奏效了,无论是告诉 tableView 重新加载数据还是直接改变它。你正在做的事情是不正确的。你到底想做什么?
    • 当然。我的 headerview 有一个最初比 headerview 高的子视图。当我将标题视图的高度调整到显示该子视图的位置时,该子视图不可见。在您滚动某处之前,它实际上不会在屏幕上绘制它。当我然后调整该标题的高度以再次覆盖它时也是如此。您必须滚动才能使其隐藏。
    • 没有任何代码我真的帮不上什么忙。为什么 subview 最初比 headerview 大?您应该在添加之前调整子视图的大小。
    • 你说得对,迈克,在我真正需要它之前,即使有那个子视图也可能是愚蠢和浪费的。我会尝试这种方法,并报告回来。我有一种感觉,它会奏效。最好的。
    猜你喜欢
    • 2012-08-01
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多