Добавление неизвестного количества строк в «Статические ячейки» 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]; } 

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

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

 -(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].

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

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

В controllerе представления для статической таблицы переопределите количество ячеек, возвращаемых для вашего динамического раздела, но примите значения по умолчанию для всех остальных разделов (они вернутся к значениям 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 

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

введите описание изображения здесь

 #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"; } 

Я отправлю ответ в 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 

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

Весь мой controller выглядит так:

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

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

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

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

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

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

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

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

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

[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" для Cell Identifier заголовка раздела 1, а затем имею что-то вроде
  - (UIView *) tableView: (UITableView *) tableView viewForHeaderInSection: (NSInteger) раздел
 {
     NSString * identifier = [NSString stringWithFormat: @ "Cell% d-Header", раздел];
     UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: идентификатор];
     return cell.contentView;
 } 

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

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

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

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

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

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

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

  • Странная проблема сравнения поплавков в объективе-C
  • iTunes Connect API
  • Как проверить программно, если приложение установлено?
  • Каков наилучший способ перетащить NSMutableArray?
  • Проблема с кодом: строка формата не является строковым литералом
  • Должен ли я использовать NSUserDefaults или plist для хранения данных?
  • MKAnnotation, простой пример
  • iPhone SDK: в чем разница между loadView и viewDidLoad?
  • UITableView, прокрутите вниз до перезагрузки?
  • NULL против нуля в Objective-C
  • Замена на устаревший размерWithFont: в iOS 7?
  • Давайте будем гением компьютера.