2012-03-31 53 views
2

我有一個多節的tableview。在編輯模式中,我允許將行從一個部分移動到另一個部分。一旦最後一行從一個部分刪除,我刪除該部分。所以我使用moveRowAtIndexPath中的deleteSection。將最後一行移出部分和刪除部分時的奇怪動畫

當最終項目從該部分移開時,部分標題按計劃消失。但是有一個非常奇怪的動畫錯誤,其中被移動的行似乎與其上面放置的行「合併」,並且在「to」部分的底部顯示了空行(可能是因爲該部分的numberOfRows是正確,但2行在同一位置)。更奇怪的是,當我點擊該行的重新排序控件(不移動項目,只是觸摸並釋放)時,兩個項目「unmerge」。

我發佈了一個video演示這個。

我試過包裝我的數據更改並查看開始/結束更新中的更改,但無濟於事。

我上傳了一個測試項目here,我也會發佈下面的代碼。幾點:

  • 我試圖在演示項目中複製我的數據源的格式,以防發生問題。關鍵是我的源碼是兩個其他數組的複合數組(儘管我不明白爲什麼這會是一個問題)。
  • 要查看有問題的行爲,請將底部的兩行移動到頂部。不要將它們放在頂部的最後一行,因爲這似乎工作正常。
  • 從上面的部分到下面的部分以另一種方式移動行,在這個演示項目中是錯誤的。

代碼(這一切都是在演示項目):

我的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; 
} 

它允許非常簡單的ro WS /部分:

- (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]; 
     } 
    } 
+1

你爲什麼要-loadView設置您的陣列?如果以編程方式創建視圖,則應該只覆蓋-loadView。沒有?並且調用[super loadView]嘗試加載與所討論的視圖控制器相同名稱的筆尖。爲什麼不把你的數組設置移動到-viewDidLoad? – 2012-04-03 01:58:43

+0

感謝 - 任何鏈接/更多信息爲什麼這是/這個規則來自哪裏?當然沒有幫助我的問題,但謝謝你的提示。 – 2012-04-03 02:18:35

+0

,因爲如果您在nib中設置視圖,loadView會被操作系統調用。該方法的文檔明確指出不直接調用此方法,並且不要覆蓋如果從nib加載視圖。 – jmstone617 2012-04-04 16:06:06

回答

3

我注意到,來自待刪除部分的行是在您潤飾訂單控制之前消失的行。

我懷疑,當這個數據源方法被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'和任何調用堆棧它恰好在刪除調用之前完成其邏輯

+0

謝謝。作爲解決方案與使用performSelector相比,這是如何進行比較的:withObject:afterDelay:?是否有任何優點/缺點? PS我覺得有一個);缺失 - 由於最少有6個字符,我的編輯過於小巧 – 2012-04-06 14:56:25

+0

經過一段時間的閱讀,看起來GCD確實是一種新穎而有光澤的方式。再次感謝! – 2012-04-06 15:01:24

+1

performSelector變體的缺點是它限制了可能使用的方法簽名。這裏沒有問題,但是如果你需要調用兩個方法或者一個帶有3個參數的方法,你將無法用performSelector來完成。否則,在這種情況下,延遲0.0基本相同(儘快運行,但在下一次運行循環期間) – bobDevil 2012-04-06 15:31:17

0

在關閉的機會他們可以關注,你有沒有檢查過你叫resignFirstResponder[view endEditing:YES]?當我們使用文本字段和(IIRC它也取決於iOS 4版本)時,我們看到了這一點,將焦點留在其中一個字段中。

+0

下面的回覆我確定我的測試項目沒有包括這樣的東西(剛剛添加)。 (還是)感謝你的建議。 – 2012-03-31 21:42:42

0

您必須在刪除該部分後重新加載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]; 
     } 

    } 
+0

我不想失去動畫,也不能解釋我所看到的行爲。在我的應用程序的其他地方,我可以刪除帶有動畫的部分,只有當我嘗試在moveRow方法中嘗試這樣做時,纔會發現問題。 – 2012-04-02 15:31:38

0

掉在你的代碼fromArraytoArray的順序。如果該項目在將其從陣列中移除之前保留計數爲1,那麼在將其添加到toArray之前,該項目的保留計數爲0。

如果交換訂單,該項目將從保留計數1到2,然後在刪除完成時返回1。

+0

感謝您的提示,但這似乎沒有任何區別。如果它是重要的,我正在使用ARC。 – 2012-04-02 15:59:32

0

我認爲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]; 
    } 
} 
1

你的問題是在動畫中。一個正在完成,而另一個尚未完成(移動&刪除動畫)導致一個單元被另一個單元劃分。您可以通過再次移動單元格來驗證這一點。然後顯示正確的順序。據蘋果在UITableView中的docs

注:數據源不應該叫setEditing:動畫:從實施的tableView的範圍內:commitEditingStyle:forRowAtIndexPath :.如果由於某種原因,它必須在延遲之後通過使用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]; 
} 

應該正常工作。只需將延遲更改爲適合您的更短的時間即可。

0

上最後一行丟失動畫的解決方案:

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]; 


    }