2013-09-27 6 views
0

У меня довольно простой UITableView с ровно 20 элементами (размер их инвентаря в игре). Моя пользовательская ячейка таблицы достаточно умна, чтобы отображать текст «SLOT EMPTY» для ячеек, которые представляют слоты инвентаря, которые не содержат элементов. У меня есть рабочее решение, но мне хотелось знать, есть ли лучший способ справиться с этим.Удаление элементов из UITableView (без их удаления)

Предназначенный результат

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

Bellybutton fuzz 
Petrified weasel snout 
Chocolate covered toilet seat 
Coupon for a high-five from Chase 
SLOT 5 EMPTY 
SLOT 6 EMPTY 
. 
. 
. 
SLOT 20 EMPTY 

Если пользователь удаляет стульчак то список должен выглядеть следующим образом:

Bellybutton fuzz 
Petrified weasel snout 
Coupon for a high-five from Chase 
SLOT 4 EMPTY 
SLOT 5 EMPTY 
. 
. 
. 
SLOT 20 EMPTY 

Примечание что список по-прежнему содержит 20 ячеек после удаления, когда используемые ячейки сдвинуты вверх, чтобы занять три верхних слота инвентаря.

Проблема

Моя первая попытка была использовать, чтобы использовать [tableView deleteRowsAtIndexPaths:withRowAnimation:] и корректировать свои данные аккомпанемента, чтобы отразить новое содержание (один меньше предмет инвентаря, один дополнительный пустой слот.) Тем не менее, это разбился с следующее исключение: (?)

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', 
reason: 'Invalid update: invalid number of rows in section 0. The number of rows 
contained in an existing section after the update (20) must be equal to the number 
of rows contained in that section before the update (20), plus or minus the number 
of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or 
minus the number of rows moved into or out of that section (0 moved in, 0 moved out).' 

раствор

[Обратите внимание, что код в го раздел упрощен от фактического кода для ясности - вопрос о методе решения, а не о конкретных деталях реализации.]

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

Удаление элемента выглядит следующим образом:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (editingStyle == UITableViewCellEditingStyleDelete) 
    { 
     NSDictionary *item = [self itemForRowAtIndexPath:indexPath]; 
     if (!item) return; 

     // Keep track of the deleted item count 
     self.mDeletedEntries += 1; 

     [tableView beginUpdates]; 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop]; 
     [tableView endUpdates]; 

     // Remove it from the data store 
     [Inventory removeInventoryItem:item]; 
    } 
} 

Позже я заменить недостающие элементы:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    // If we have deleted some entries and need to add some new ones, schedule 
    // a process to insert them. 
    // 
    // *This is what feels like a hack to me* 
    if (self.mDeletedEntries) 
    { 
     [self performSelector:@selector(addEmptySlots:) withObject:tableView afterDelay:0]; 
    } 

    // Return the current count that IOS wants (inventory size minus the deleted ones) 
    return kUserMaxInventorySize - self.mDeletedEntries; 
} 

- (void)addEmptySlots:(UITableView *)tableView 
{ 
    // We start adding entries into the list at the end 
    int insertLocation = kUserMaxInventorySize - self.mDeletedEntries; 

    [tableView beginUpdates]; 

    // Add the deleted entries (should only ever be 1 entry, really)  
    for (int i = 0; i < self.mDeletedEntries; ++i) 
    { 
     // They get added to the end of the table 
     NSIndexPath *path = [NSIndexPath indexPathForRow:insertLocation + i inSection:0]; 
     NSArray *indexArray = [NSArray arrayWithObjects:path,nil]; 

     // Insert the entry. We don't need to actually add the item to our data store, 
     // since empty entries will simply report "Slot empty" text. 
     [tableView insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationBottom]; 
    } 

    // These are no longer deleted 
    self.mDeletedEntries = 0; 

    [tableView endUpdates]; 
} 

Это работает, но это лучший способ для достижения этой цели?

+0

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

+0

Как насчет простого NSMutableArray с 20 объектами NSString, содержащими 'SLOT% d EMPTY' изначально, а затем начать замену объектов на реальные объекты. При удалении замените его на строку. –

+0

@HotLicks Проблема с reloadData заключается в том, что вы теряете возможность анимировать элемент в списке. У меня было много других проблем с этим, в том числе некоторые ЧРЕЗВЫЧАЙНЫЕ нечетные результаты от ячеек, перемещающихся в верхнюю часть таблицы, и запуск подпрыгивающей анимации позади ячейки, которая уже была наверху. Очень странно. – pauln

ответ

0

Я думаю, что ваш подход делает это более сложным, чем это должно быть. Например, вы сказали, что у вашего tableview всегда будет ровно 20 ячеек. Почему не `- (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) раздел 'просто возвращает 20?

Я не уверен, как вы храните предметы в инвентаре. Я просто напишу свои примеры, как будто у вас есть NSMutableArray с именем inventory.

Я бы просто всегда возвращал 20 как количество строк.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return 20; 
} 

В cellForRowAtIndexPath проверки, чтобы увидеть, если элемент существует строку, которую вы создаете ячейку для или если вы должны создать «SLOT EMPTY» клетки:

– tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    ... 
    if ([indexPath row] < [inventory count]) { 
     // configure a cell that represents actual inventory 
     NSDictionary *item = [inventory objectAtIndex:[indexPath row]]; 
     ... 
    } else { 
     // configure a "SLOT * EMPTY" cell 
     NSUInteger slotNumber = [indexPath row] - [inventory count] + 1; 
     ... 
    } 
    ... 
} 

При удалении элемента удалить его из вашего массива, удалить строку, и добавить строку в нижней части Tableview принять это место:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    if (editingStyle == UITableViewCellEditingStyleDelete) 
    { 
     // Remove it from the data store 
     [inventory removeObjectAtIndex:[indexPath row]]; 

     [tableView beginUpdates]; 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop]; 
     // you also need to insert a row at the bottom so the number of rows is correct 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:19 inSection:0] withRowAnimation:UITableViewRowAnimationTop]; 
     [tableView endUpdates]; 
    } 
} 
+0

Спасибо Алекс! Вы абсолютно правы - я просто не думал вставлять записи во время процесса обновления, который удалял элементы инвентаря. Трюк в моем случае состоял в том, чтобы вставить новую запись сразу после последнего фактического элемента инвентаря (после удаления), а не в конце списка. Однако это конкретная реализация. – pauln

+0

Я рад, что смог помочь! – Alex

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