Добавление неизвестного количества строк в "Статические ячейки" 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];
}
Как я могу оставить существующие разделы такими, какие они есть, но добавить дополнительный с несколькими ячейками?
Ответы
Ответ 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 строк.
Я допускаю, что не является динамическим в абсолютном смысле слова, но, возможно, решает большинство случаев.