![](/img/trans.png)
[英]NSInternalInconsistencyException when last row is removed from the section
[英]Strange animation when moving last row out of section and deleting section
我有一個多部分的tableview。 在編輯模式下,我允許將行從一個部分移到另一部分。 將最后一行從一個部分中刪除后,我將刪除該部分。 所以我在moveRowAtIndexPath內部使用deleteSection。
當最后一個項目從節中移出時,節標題將按計划消失。 但是有一個非常奇怪的動畫錯誤,其中移動的行似乎與它上方的行“合並”,並且在“ to”部分的底部顯示一個空行(可能是因為該部分的numberOfRows為正確,但2行位於同一位置)。 甚至更陌生,當我單擊該行的重新排序控件(不移動項目,只需觸摸並釋放)時,兩個項目“合並”。
我發布了一個視頻來演示這一點。
我嘗試包裝我的數據更改並在開始/結束更新中查看更改,但無濟於事。
我已經在這里上傳了一個測試項目,我還將在下面發布代碼。 要點:
代碼(所有這些都在演示項目中):
我在loadView中設置了數組:
- (void)loadView{
array1 = [NSMutableArray array];
[array1 addObject:@"test 0"];
[array1 addObject:@"test 1"];
[array1 addObject:@"test 2"];
array2 = [NSMutableArray array];
[array2 addObject:@"test a"];
[array2 addObject:@"test b"];
[super loadView];
}
我也有一個返回這些數組組合的方法-用作數據源:
- (NSMutableArray *)sourceArray{
NSMutableArray *result = [NSMutableArray array];
if (array1.count > 0) {
[result addObject:array1];
}
if (array2.count >0) {
[result addObject:array2];
}
return result;
}
這使得行/節的數量非常簡單:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return self.sourceArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[self.sourceArray objectAtIndex:section] count];
}
標准單元格/標題格式:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [[self.sourceArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:@"Section %i", section];
}
這是我做魔術的地方
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
我注意到,來自待刪除部分的行將消失,直到您修改訂單控件。
我懷疑當tableview調用此數據源方法時,它的狀態仍處於執行移動的中間,因此調用'deleteSections'將使表嘗試刪除正在移動的行。 它並沒有太大的合並,因為它以與節標題相同的速率逐漸消失,而它下面的那個只是在回彈以填充空間。
輕擊控件會使表視圖重新調整自身位置,並意識到該行實際上並未消失。
要嘗試解決此問題,請嘗試通過調度調用在下一個runloop中運行刪除操作,例如:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
dispatch_async(dispatch_get_main_queue(), ^() {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
});
}
這將導致刪除操作仍在主線程上運行,但允許'moveRow'及其碰巧發生的任何調用棧在刪除調用之前完成其邏輯
您的問題出在動畫上。 一個正在完成而另一個尚未完成(移動和刪除動畫),導致一個單元格被繪制在另一個單元格上。 您可以通過再次移動單元格來驗證這一點。 然后將顯示正確的順序。 根據Apple在UITableView上的文檔 :
注意:數據源不應在tableView:commitEditingStyle:forRowAtIndexPath:的實現中調用setEditing:animated:。 如果出於某種原因,它必須在延遲后通過使用performSelector:withObject:afterDelay:方法來調用它。
因此,要解決此問題,請對您的代碼執行以下操作:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:@selector(someMethod:) withObject:fromIndexPath afterDelay:1.0];
}
- (void) someMethod:(NSIndexPath *) fromIndexPath {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
應該工作正常。 只需將延遲更改為更適合您的時間即可。
我認為UITableViewRowAnimationFade動畫會干擾UITableViewCell移動動畫。 您可以嘗試做的一件事是延遲部分刪除,以使單元格移動行動畫完成。
嘗試用以下代碼替換您的代碼。
-(void)deleteSection:(NSIndexSet*)indexSet
{
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:@selector(deleteSection:) withObject:[NSIndexSet indexSetWithIndex:fromIndexPath.section] afterDelay:1.0];
// [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
在最后一行丟失動畫的解決方案:
if([listOfItemsOnTransaction count]==indexPath.row){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
}
如果行或行中的內容可以引起焦點,您是否檢查過是否調用過resignFirstResponder
或[view endEditing:YES]
? 我們在使用文本字段時看到了這一點,並且(IIRC也依賴於iOS 4版本)將焦點放在其中一個字段上。
刪除該部分后,您必須重新加載tableview。 試試這個代碼。
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
在代碼中交換fromArray
和toArray
的順序。 如果該項目從數組中取出具有現有的1一個保留計數,它將具有其添加到之前一個保留的0計數toArray
。
如果您交換訂單,則該項目將從保留計數1變為2,然后在刪除完成后返回1。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.