2012-04-06 2 views
36

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

Прежде всего, как только я раскомментирую стандартные методы делегатов таблицы, которые вставлены 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]; 
} 

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

+0

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

+0

Возвращает [super tableView: tableView numberOfRowsInSection: section]; не возвращать количество строк в каждом разделе? – Darren

+0

Выше методы - это когда вы используете ячейки прототипа (dequeueReusableCellWithIdentifier). Вы используете статические ячейки. – Canopus

ответ

48

Для добавления динамических ячеек в таблицу статической ячеек вы должны переопределить каждый метод делегата 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's 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].

+3

На самом деле, если вы хотите создать столько разделов, сколько хотите динамически, вам нужно реализовать 'numberOfSectionsInTableView:' тоже. И чтобы решить проблему выхода из границ массива, вам нужно будет переопределить ВСЕ методы с помощью indexPath! Некоторые из них не перечислены здесь, например 'titleForHeaderInSection' или' heightForHeaderInSection' и 'viewForHeaderInSection'. – DanSkeel

+0

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

+0

Это работает для меня, но только частично. Вместо отображения пользовательской ячейки в таблице отображается пустая ячейка (с правильным размером и т. Д.). Из того, что я испытал, я могу сказать, что 'dequeueReusableCellWithIdentifier' всегда возвращает' nil' в статической таблице, поэтому мы остаемся только с 'cellForRowAtIndexPath', что не помогает, потому что мы хотим добавить больше ячеек в этот раздел, а не измените те, которые у нас уже есть. Таким образом, мы вручную создаем новые ячейки с помощью MyCustomCell * cell = [super.tableView dequeueReusableCellWithIdentifier: @ MyCustomCellId "];', который также НЕ работает. Любые подсказки? – jweyrich

0

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

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

Спасибо. Я сказал в комментариях, что у меня это отсортировано сейчас. – Darren

+0

OK круто! Извините, я пропустил это –

10

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

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

В контроллере представления для статической таблицы переопределите количество ячеек, возвращаемых для вашего динамического раздела, но принимайте значения по умолчанию для всех остальных разделов (они вернутся к значениям IB). Сделайте то же самое для cellForRowAtIndexPath и вернуть реализацию [супер] для всех разделов кроме раздела 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 
0

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

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

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

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

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

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

[super.tableView dequeueReusableCellWithIdentifier:CellIdentifier]

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

---

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

  • Использование Prototype Table View с Cell идентификаторами, как «31» для Раздела 3 строки 1. Затем я могу сделать что-то вроде
NSString *identifier = [NSString stringWithFormat:@"%d%d", indexPath.section, indexPath.row]; 
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  • Использование прототипных ячеек также для заголовков. Я использую "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.

0

Я думаю, что нашел лучшее и более простое решение, с секциями или рядами «fantom» в IB.

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

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

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

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

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

6

Я думал, что добавлю обновленный ответ на основе превосходного ответа Даррена. Большинство методов делегатов не требуются. Итак, я просто добавил необходимые. Вы можете легко добавить пользовательскую ячейку, если хотите, даже используя файл 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"; 
    } 
+0

Спасибо за этот ответ. Стоит отметить, что если вы используете раскадровку, тогда для этого ответа требуется, чтобы раздел 2 табличного представления содержал по крайней мере одну ячейку, из которой можно получить высоту ячейки. В противном случае он выйдет из строя из-за пределов ...! – fatuhoku

+0

Я также обнаружил, что переопределение Tableview: heightForRowAtIndexPath: метод делегата требуется (под прошивкой 9, по крайней мере!) @smileBot: // требуется - (CGFloat) Tableview: (UITableView *) Tableview heightForRowAtIndexPath: (NSIndexPath *) indexPath { Раздел NSInteger = indexPath.section; if (section == DYNAMIC_SECTION) { return [super tableView: tableView heightForRowAtIndexPath: [NSIndexPath indexPathForRow: 0 inSection: section]]; } else { return [super tableView: tableView heightForRowAtIndexPath: indexPath]; } } – fatuhoku

+2

Я создал проект, который демонстрирует это: https://github.com/fatuhoku/demo-ios-hybrid-static-and-dynamic-uitableview – fatuhoku

5

Я отправлю ответ на 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 также с пером, и зарегистрируйте его в виде таблицы.

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

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() 
    } 
} 
+0

Где «CustomCell» и «ReuseIdentifier» " родом из? – Josh

+0

Этот подход работал для меня. Я столкнулся с ошибками, пока не перечеркнул indentationLevelForRowAtIndexPath. – protasm

Смежные вопросы