Подтвердить что ты не робот

Добавление неизвестного количества строк в "Статические ячейки" UITableView

У меня есть статическая таблица, созданная в Interface Builder с 6 разделами с разным количеством строк. Теперь я хочу добавить 7-ю секцию с различным количеством строк.

Прежде всего, как только я раскомментирую стандартные методы делегата таблицы, которые вставлены Xcode, я получаю сбой в self.tableView.tableHeaderView = containerView; где я добавил заголовок в таблицу.

Более того, я получаю сбой со следующим кодом

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 7;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section==6) {
        return 4;
    } else {
        return [super tableView:tableView numberOfRowsInSection:section];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{/*
    if (indexPath.section == 6) {
        static NSString *CellIdentifier = @"cellWireless";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        // Configure the cell...

        return cell;
    }*/
    return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}

Как я могу оставить существующие разделы такими, какие они есть, но добавить дополнительный с несколькими ячейками?

4b9b3361

Ответ 1

Чтобы добавить динамические ячейки в таблицу статических ячеек, вы должны переопределить каждый метод делегата UITableView, который имеет indexPath.

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath

-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath

-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
-(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

.

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
     return NO;
}

-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{     
     return NO;
}

-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{     
     return UITableViewCellEditingStyleNone;     
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
     int section = indexPath.section;

     // if dynamic section make all rows the same height as row 0
     if (section == self.dynamicSection) {
          return [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
     } else {
          return [super tableView:tableView heightForRowAtIndexPath:indexPath];
     }
}

- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
     int section = indexPath.section;

     // if dynamic section make all rows the same indentation level as row 0
     if (section == self.dynamicSection) {
          return [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
     } else {
          return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
     }
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
     if (section == self.dynamicSection ) {
          return [self.dataListArray count];
     } else {
          return [super tableView:tableView numberOfRowsInSection:section];
     }
}

-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
     int section = indexPath.section;
     int row = indexPath.row;


     if (section == self.dynamicSection) {
          // make dynamic row cell
          static NSString *CellIdentifier = @"Dynamic Cell";
          UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

          if (!cell) {
               cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
          }

          cell.textLabel.text = [self.dataListArray objectAtIndex:row];
          return cell;
    } else {
          return [super tableView:tableView cellForRowAtIndexPath:indexPath];
    }
}

Только после того, как вы переопределите каждый метод, ваша таблица начнет работать. Для любых ссылок на статический раздел просто обратитесь к [super].

Ответ 2

Ответ Darren дал мне идею того, что сработало для меня, однако мне не пришлось заходить так далеко, чтобы реализовать каждый метод делегата tableView. Вам действительно нужно переопределить numberOfRowsInSection и cellForRowAtIndexPath.

Сначала я определил статическую таблицу в Interface Builder с 4 разделами, от 2 до 4 ячеек на раздел. Я хотел бы, чтобы разделы 0, 2 и 3 были статическими и выглядели точно так же, как в IB, но я хотел, чтобы раздел 1 имел собственное количество строк с пользовательским отображением в каждой ячейке на основе массива значений, которые у меня были.

В контроллере представления для статической таблицы переопределите количество ячеек, возвращаемых для вашего динамического раздела, но примите значения по умолчанию для всех остальных разделов (они вернутся к значениям IB). Сделайте то же самое для cellForRowAtIndexPath и верните реализацию [super] для всех разделов, кроме раздела 1.

@implementation myMostlyStaticTableViewController
@synthesize myFancyArray;

- (NSInteger) tableView:(UITableView *) tableView numberOfRowsInSection:(NSInteger) section
{
    if (section == 1)
        return [myFancyArray count]; // the number of rows in section 1
    else
        return [super tableView:tableView numberOfRowsInSection:section];
}

- (UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
    // for cells not in section 1, rely on the IB definition of the cell
    if (indexPath.section != 1)
        return [super tableView:tableView cellForRowAtIndexPath:indexPath];

    // configure a task status cell for section 1
    MyCustomTableViewCell *cell;
    cell = [tableView dequeueReusableCellWithIdentifier:@"myCustomCell"];
    if (!cell)
    {
        // create a cell
        cell = [[MyCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"myCustomCell"];
    }
    cell.myCustomLabel.text = [myFancyArray objectAtIndex:indexPath.row];
    return cell;
}
@end

И, конечно, вам нужна специальная ячейка:

@implementation MyCustomTableViewCell

- (UITableViewCell *) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    // initialize cell and add observers
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (!self)
        return self;
    self.clipsToBounds = YES;
    self.selectionStyle = UITableViewCellSelectionStyleNone;

    // configure up some interesting display properties inside the cell
    _label = [[UILabel alloc] initWithFrame:CGRectMake(20, 9, 147, 26)];
    _label.font = [UIFont fontWithName:@"HelveticaNeue-Medium" size:17];
    _label.textColor = [UIColor colorWithWhite:0.2 alpha:1];
    [self.contentView addSubview:_label];

    return self;
}

@end

Ответ 3

Я думал, что добавлю обновленный ответ, основанный на превосходном ответе @Darren. Большинство методов делегатов не требуются. Итак, я просто добавил необходимые. Вы можете легко добавить пользовательскую ячейку, если хотите, даже используя файл nib. На изображении показана статическая таблица с тремя разделами. Заключительный раздел - динамическое время выполнения. Это очень удобно. Это работает в iOS7 BTW.

enter image description here

#define DYNAMIC_SECTION 2

#import "MyTableViewController.h"

@interface MyTableViewController ()
@property (strong, nonatomic)NSArray *myArray;
@end

@implementation MyTableViewController

- (id)initWithCoder:(NSCoder *)aDecoder
    {
        if (self = [super initWithCoder:aDecoder]) {
            _myArray = @[@"ONE", @"TWO", @"THREE", @"FOUR"];
        }
        return self;
    }

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [super numberOfSectionsInTableView:tableView];
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        if (section != DYNAMIC_SECTION) {
            return [super tableView:tableView numberOfRowsInSection:section];
        }
        return [self.myArray count];
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.section != DYNAMIC_SECTION) {
            return [super tableView:tableView cellForRowAtIndexPath:indexPath];
        }
        static NSString *id = @"MyCell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:id];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:id];
        }
        cell.textLabel.text = self.myArray[indexPath.row];
        return cell;
    }

        // required
    -(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        int section = indexPath.section;
        if (section == DYNAMIC_SECTION) {
            return [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
        } else {
            return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
        }
    }

            // Not required
    - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
        if (section != DYNAMIC_SECTION) {
            return [super tableView:tableView titleForHeaderInSection:section];
        }
        return @"some title";
    }

Ответ 4

Я отправлю ответ в Swift, но он должен работать и в Objective-C.

По моему опыту, было достаточно переопределить эти методы в UITableViewController:

tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
tableView(tableView: UITableView, indentationLevelForRowAtIndexPath indexPath: NSIndexPath) -> Int

Если вы хотите иметь пользовательскую ячейку вида таблицы в представлении таблицы, вам нужно подделать подкласс UITableViewCell также с помощью nib и зарегистрировать его в виде таблицы.

Весь мой контроллер выглядит следующим образом:

var data = ["Ahoj", "Hola", "Hello"]

override func viewDidLoad() {
    super.viewDidLoad()

    tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
}

// MARK: - Table view data source

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 1 {
        return data.count
    }
    return super.tableView(tableView, numberOfRowsInSection: section)
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.section == 1 {
        let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as! CustomCell
        cell.titleLabel.text = data[indexPath.row]
        return cell
    }
    return super.tableView(tableView, cellForRowAtIndexPath: indexPath)
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 44
}

override func tableView(tableView: UITableView, indentationLevelForRowAtIndexPath indexPath: NSIndexPath) -> Int {
    return 0
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
    if indexPath.section == 1 {
        print(data[indexPath.row])
    }
}

@IBAction func addItem() {
    data.append("Item \(data.count)")
    tableView.beginUpdates()
    tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: data.count - 1, inSection: 1)], withRowAnimation: .Left)
    tableView.endUpdates()
}

@IBAction func removeItem() {
    if data.count > 0 {
        data.removeLast()
        tableView.beginUpdates()
        tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: data.count, inSection: 1)], withRowAnimation: .Left)
        tableView.endUpdates()
    }
}

Ответ 5

Я думаю, вам нужно будет сделать свой UITableView динамический. Если у вас есть "неизвестное" количество строк, вы, скорее всего, установите для метода делегата что-то вроде этого:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [someArray count];
}

Ответ 6

Я обнаружил что-то довольно интересное, я думаю, и это больше стоит ответа, чем "комментарий". У меня был статический tableView с динамическими рядами, а затем он переставал работать. Причина проста. Я ранее имел

[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]

а позже решил, что мне нужна/нужна специальная ячейка, которую я создавал бы в своем StoryBoard, и только установил розетки для моего подкласса UITableView. Поэтому я использовал другую технику

[super tableView:tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.section]];

Проблема здесь в том, что эта ячейка повторно используется, и, таким образом, вы будете видеть только одну из ячеек за раз. Когда-нибудь вы даже не увидите никого, они все будут пусты! Если вы прокрутите список, вы увидите, что в ближайшее время появятся другие ячейки, а затем исчезнет (больше похоже на мерцание!).

Это сильно заставило меня задуматься, пока я не понял, что было (им) возможным. Кроме того, не пытайтесь делать

[super.tableView dequeueReusableCellWithIdentifier:CellIdentifier]

поскольку, как упоминалось другими людьми, это всегда возвращает nil в статическом tableView.

---

Поэтому я не уверен, что делать. Я предполагаю, что буду использовать "статический прототип", который состоит из

  • Использование представления таблицы Prototype с идентификаторами ячеек типа 31 для раздела 3 Строка 1. Затем я могу сделать что-то вроде
NSString *identifier = [NSString stringWithFormat:@"%d%d", indexPath.section, indexPath.row];
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  • Используйте Prototype Cells также для заголовков. Я использую "Cell1-Header" для Идентификатора ячейки заголовка раздела 1, а затем имею что-то вроде
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    NSString *identifier = [NSString stringWithFormat:@"Cell%d-Header", section];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    return cell.contentView;
}

Самое главное, что вы можете начинать с статического tableView, но в тот момент, когда вы понимаете, что вам нужно что-то динамическое, замените его на Prototype (он будет держать ваши строки, хотя я не помню что он делает с разделами!) и используйте эту технику KISS.

Ответ 7

Думаю, я нашел лучшее и простое решение, с секциями или строками "fantom" в IB.

Если вы знаете максимальное количество ячеек, которое вы будете использовать в разделе 7 (скажем, 10), вы должны установить количество строк до 10, когда вы настраиваете раздел 7 в IB.

Вы не должны использовать все 10 строк в секции, это может быть установлено

 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section.

Например, если вы вернете 5, когда раздел == 6 (фактически седьмой раздел), то отобразятся только 5 строк.

Я допускаю, что не является динамическим в абсолютном смысле слова, но, возможно, решает большинство случаев.