LoginSignup
51
51

More than 5 years have passed since last update.

UITableViewのセクション数と行数を動的に変える方法

Last updated at Posted at 2012-11-13

UITableViewStyleGroupedにしているUITableViewでたまにやりたくなるけど意外と面倒くさいパターンです。

まずはenumで各セクションと各行に名前を振る

これは動的じゃない場合も、面倒臭がらずにやっておくと後々楽です。
今作ってるアイテム詳細画面の場合、こんな感じ。

// section index
enum {
    kItemDetailSectionImage = 0,
    kItemDetailSectionLike,
    kItemDetailSectionMemo,
    kItemDetailSectionInfo,
    kItemDetailSectionComment,
    kItemDetailSectionAddComment
};
// row index
enum {
    kItemDetailRowName = 0,
    kItemDetailRowImage,
    kItemDetailRowCountry,
    kItemDetailRowLike = 0,
    kItemDetailRowTags = 0,
    kItemDetailRowMemo,
    kItemDetailRowUser,
    kItemDetailRowBoughtAt = 0,
    kItemDetailRowPrice,
    kItemDetailRowLocation,
    kItemDetailRowComments = 0,
    kItemDetailRowAddComment = 0
};

セクション数と行数を計算する処理

条件によってセクション数と行数を変えるため、表示する場所のみを格納した配列をフィールドに用意します。
下の例ではモデルself.itemの各項目が空じゃなかったら表示したいので、その場合のみ配列に番号(上で定義したenum)を追加するようにしています。

@interface ItemDetailVC ()
@property(nonatomic, strong) NSMutableArray *sectionIndices;
@property(nonatomic, strong) NSMutableArray *rowIndices;
@end
- (void)calcSection {
    self.sectionIndices = [[NSMutableArray alloc] init];
    self.rowIndices = [[NSMutableArray alloc] init];
    {
        NSMutableArray *rowTags = [[NSMutableArray alloc] init];
        if (! [Util isEmpty:self.item.name]) {
            [rowTags addObject:@(kItemDetailRowName)];
        }
        if (! [Util isEmpty:self.item.photoUrl]) {
            [rowTags addObject:@(kItemDetailRowImage)];
        }
        if (! [Util isEmpty:self.item.country]) {
            [rowTags addObject:@(kItemDetailRowCountry)];
        }
        if (rowTags.count > 0) {
            [self.rowIndices addObject:rowTags];
            [self.sectionIndices addObject:@(kItemDetailSectionImage)];
        }
    }
    {
        NSMutableArray *rowTags = [[NSMutableArray alloc] init];
        [rowTags addObject:@(kItemDetailRowLike)];

        if (rowTags.count > 0) {
            [self.rowIndices addObject:rowTags];
            [self.sectionIndices addObject:@(kItemDetailSectionLike)];
        }
    }
    {
        NSMutableArray *rowTags = [[NSMutableArray alloc] init];
        if (self.item.tags.count > 0) {
            [rowTags addObject:@(kItemDetailRowTags)];
        }
        if (! [Util isEmpty:self.item.memo]) {
            [rowTags addObject:@(kItemDetailRowMemo)];
        }
        if (! [Util isEmpty:self.item.user]) {
            [rowTags addObject:@(kItemDetailRowUser)];
        }

        if (rowTags.count > 0) {
            [self.rowIndices addObject:rowTags];
            [self.sectionIndices addObject:@(kItemDetailSectionMemo)];
        }
    }
    ...
}

でモデルが更新される度にセクション数と行数を計算し直すようにします。

- (void) refresh:(int)itemId {
    NSDictionary *params = @{
        @"id" : [NSNumber numberWithInt:itemId]
    };

    __weak ItemDetailVC *wself = self;

    [[APIClient sharedClient] getItemDetail:params success:^(id res) {
        wself.item = [[Item alloc] initWithDictionary:res];
        [wself calcSection];
        [wself.tableView reloadData];
    }];
}

UITableViewDataSourceのメソッド修正

セクション数、行数を用意した配列から読むように変更します。

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
    return [self.sectionIndices count];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.rowIndices[section] count];
}

セルの内容決定についても、以下のようにindexPathを調整してやる必要があります。

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    int section = [self.sectionIndices[indexPath.section] intValue];
    int row = [self.rowIndices[indexPath.section][indexPath.row] intValue];

    NSString *cellId = @"ItemDetailCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellId];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    switch (section) {
        case kItemDetailSectionImage:
            switch (row) {
                case kItemDetailRowName:
                    cell.textLabel.text = @"名前";
                    cell.detailTextLabel.text = self.item.name;
                    break;
                case kItemDetailRowCountry:
                    cell.textLabel.text = @"国";
                    cell.detailTextLabel.text = self.item.country.name;
                    break;
                ...
            }   break;
        ...
    }
    return cell;
}

以上

ざっとこんな感じですが、けっこう大変。。
もうちょっとエレガントな方法はないすかねぇ。

51
51
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
51