2012-10-04 131 views
1

我有一個UITableView代表項目清單。每個項目都處於完成/撤消狀態。UITableView延遲reloadData直到動畫完成

我想將所有已完成的項目都保留在列表頂部,因此當用戶單擊已取消的項目時,我想知道該行應該放在哪裏(在當前 - 完成項目列表)並將其移動到那裏。

我想爲我的UITableView使用-moveRowAtIndexPath:toIndexPath:來做到這一點。

它有時運作良好,在其他時間不太好。

當完成的操作在屏幕上的其他位置啓動另一個動畫時,它似乎可以正常工作。出於某種原因,這似乎是-reloadData調用的延遲。

如果這不是真的(即唯一發生的事情是被標記爲已完成並正在移動的行),則動畫似乎通過自動調用UITableView的方法而被短路。也就是說,動畫開始,但大約一半的時候,-reloadData被調用,行被捕捉到它們的最終位置。從用戶的角度來看,這相當震撼。

我跟蹤了我的代碼,確認我自己並沒有打電話-reloadData,也沒有看到我是觸發此-reloadData調用的人。

我可以自動撥打-reloadData,我明白爲什麼會這麼叫(雖然你認爲這可能沒有必要,但這是一個不同的問題),但我真的很喜歡它,直到它完成其動畫。

下面是我使用的代碼:

NSIndexPath *oldPath = [NSIndexPath indexPathForRow:currentIndex inSection:0]; 
NSIndexPath *newPath = [NSIndexPath indexPathForRow:newIndex  inSection:0]; 

[tableView beginUpdates]; 

[checklist removeObject:task]; 
[checklist insertObject:task atIndex:newIndex]; 
[tableView moveRowAtIndexPath:oldPath toIndexPath:newPath]; 

[tableView endUpdates]; 

上午我擰東西了?

+0

Doh!我真的是手動調用'-reloadData'。這是微妙的,從一個計時器,這是沒有達到斷點啓用。衛生署!衛生署!衛生署! ;-) – mbm29414

+1

請添加您的解決方案作爲對此問題的答案並接受它。 – titaniumdecoy

回答

0

在titaniumdecoy的要求,這裏就是我得到了這個問題固定:

我有一個UIViewController子與NSTimer執行一次,第二次,檢查一個UITableView底層數據源作爲指示呼叫變化到-reloadData是必要的。所以,該子類我說:

@property (BOOL) IsAnimating; 

我最初將其設置爲NO,如果isAnimating屬性設置爲YES,該NSTimer「短路」,並跳過正常處理。

所以,當我想運行這個UITableView動畫時,我將isAnimating屬性設置爲YES並運行動畫。

然後,我安排一個選擇器在未來運行1秒,將isAnimating重置爲NO。然後NSTimer將繼續觸發,並將看到的isAnimating(最有可能在第二次後續呼叫-codeTimerFired),然後找到數據源更新,開始撥打電話reloadData

下面是用於懸掛NSTimer的處理以及調度所述UITableView動畫的代碼:

// currentIndex and newIndex have already been calculated as the data item's 
// original and destination indices (only 1 section in UITableView) 
if (currentIndex != newIndex) { 

    // This item's index has changed, so animate its movement 
    NSIndexPath *oldPath = [NSIndexPath indexPathForRow:currentIndex inSection:0]; 
    NSIndexPath *newPath = [NSIndexPath indexPathForRow:newIndex  inSection:0]; 

    // Set a flag to disable data source processing and calls to [UITableView reloadData] 
    [[self Owner] setIsAnimating:YES]; 

    // I haven't tested enough, but some documentation leads me to believe 
    // that this particular call (-moveRowAtIndexPath:toIndexPath:) may NOT need 
    // to be wrapped in a -beginUpdates/-endUpdates block 
    [[[self Owner] InstructionsTableView] beginUpdates]; 

    // These lines move the item in my data source 
    [[[MMAppDelegate singleton] CurrentChecklist] removeObject:[self CellTask]]; 
    [[[MMAppDelegate singleton] CurrentChecklist] insertObject:[self CellTask] atIndex:newIndex]; 

    // This code is the UITableView animation 
    [[[self Owner] InstructionsTableView] moveRowAtIndexPath:oldPath toIndexPath:newPath]; 

    // Conclude the UITableView animation block 
    [[[self Owner] InstructionsTableView] endUpdates]; 

    // Schedule a call to re-enable UITableView animation   
    [[self Owner] performSelector:@selector(setIsAnimating:) withObject:@(NO) afterDelay:1.0]; 

} else { 
    // This location hasn't changed, so just tell my owner to reload its data 
    [[[self Owner] InstructionsTableView] reloadData]; 
} 

這裏的NSTimer方法(注意它是如何撈出如果isAnimating == YES):

- (void)codeTimerFired { 

    // This is a subclass of a template subclass... 
    // super actually has work to do in this method... 
    [super codeTimerFired]; 

    // If we're in the middle of an animation, don't update! 
    if ([self IsAnimating]) { 
     return; 
    } 

    // Other data source processing... 

    // local BOOL to check whether underlying data source has changed 
    BOOL shouldUpdate = NO; 

    // code to check if underlying data source has changed... 
    // ****************************************************** 
    // [CODE REMOVED] 
    // ****************************************************** 

    // If the underlying data source has changed, update the UITableView 
    if (shouldUpdate) { 
     [self reloadTableView]; // <--- This is the main line I wanted to prevent 
           //  since the code that fired to cause the 
           //  UITableView animation will ALWAYS cause 
           //  the underlying data source to change such 
           //  that this line would fire. 
    } 
} 
1

夫特

//--------- 
extension UITableView { 

    // Default delay time = 0.5 seconds 
    // Pass animation time interval, as a parameter argument 
    func reloadDataAfterDelay(delayTime: TimeInterval = 0.5) -> Void { 
     self.perform(#selector(self.reloadData), with: nil, afterDelay: delayTime) 
    } 

}