1

アイテムのチェックリストを表す UITableView があります。各アイテムは完了/元に戻された状態にあります。

完了したすべての項目をリストの一番上に保持したいので、ユーザーが元に戻された項目をクリックしたときに、行がどこに移動するかを把握したいと思います (現在完了している項目リストの最後) )、そこに移動します。

-moveRowAtIndexPath:toIndexPath:これを行うために UITableView を使用しようとしています。

うまくいくときもあれば、うまくいかないときもあります。

完了したアクションが画面の別の場所で別のアニメーションを開始する場合、うまく機能するようです。-reloadData何らかの理由で、これは呼び出しの遅延として機能しているようです。

そうでない場合 (つまり、「起こっている」のは行が完了とマークされて移動している場合のみ)、アニメーションは UITableView の-reloadDataメソッドへの自動呼び出しによってショートサーキットされたように見えます。つまり、アニメーションが開始されますが、途中で-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];

私は何かを台無しにしていますか?

4

2 に答える 2

1

チタンデコイのリクエストで、この問題を修正した方法は次のとおりです。

1 秒に 1 回実行されるを持つUIViewControllerサブクラスがあり、基になるデータ ソースでの呼び出しが必要であることを示す変更がないNSTimerかチェックします。そのため、そのサブクラスに次を追加しました。UITableView-reloadData

@property (BOOL) IsAnimating;

これを最初に に設定しNOisAnimatingプロパティが に設定されているYES場合、NSTimer「短絡」して通常の処理をスキップします。

したがって、このアニメーションを実行する場合は、プロパティをUITableViewに設定してアニメーションを実行します。isAnimatingYES

次に、セレクターを 1 秒後に実行するようにスケジュールします。これは にリセットさisAnimatingNOます。はNSTimerその後も発火を続け、isAnimatingofを確認しNO(おそらく の 2 回目の呼び出しで-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.
    }
}
于 2012-10-05T00:43:28.783 に答える