19

この問題に対するまともな答えを見た人はいますか?

initialLayoutAttributesForAppearingItemAtIndexPath挿入されるセルだけでなく、すべての可視セルに対して呼び出されているようです。Apple自身のドキュメントによると:

移動されたアイテムの場合、コレクション ビューは標準メソッドを使用して、アイテムの更新されたレイアウト属性を取得します。アイテムが挿入または削除されると、コレクション ビューはいくつかの異なるメソッドを呼び出します。これらのメソッドをオーバーライドして、適切なレイアウト情報を提供する必要があります。

何が起こっているようには聞こえません...他のセルは挿入されておらず、移動されていますが、移動されているセルも呼び出しinitialLayoutAttributesForAppearingItemAtIndexPathいます。

prepareForCollectionViewUpdates:どの indexPaths が更新されているかを追跡し、それらのみを変更するという回避策を見てきましたが、これは自分のドキュメントに反することは少し奇妙に思えます。他の誰かがこれを回避するより良い方法を見つけましたか?

4

4 に答える 4

25

Mark Pospesel によるこのブログ投稿が役立つことがわかりました。
筆者は WWDC のCircleLayoutサンプルも修正し、Github に投稿しました

関心のある方法:

- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems
{
    // Keep track of insert and delete index paths
    [super prepareForCollectionViewUpdates:updateItems];

    self.deleteIndexPaths = [NSMutableArray array];
    self.insertIndexPaths = [NSMutableArray array];

    for (UICollectionViewUpdateItem *update in updateItems)
    {
        if (update.updateAction == UICollectionUpdateActionDelete)
        {
            [self.deleteIndexPaths addObject:update.indexPathBeforeUpdate];
        }
        else if (update.updateAction == UICollectionUpdateActionInsert)
        {
            [self.insertIndexPaths addObject:update.indexPathAfterUpdate];
        }
    }
}

- (void)finalizeCollectionViewUpdates
{
    [super finalizeCollectionViewUpdates];
    // release the insert and delete index paths
    self.deleteIndexPaths = nil;
    self.insertIndexPaths = nil;
}

// Note: name of method changed
// Also this gets called for all visible cells (not just the inserted ones) and
// even gets called when deleting cells!
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    // Must call super
    UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];

    if ([self.insertIndexPaths containsObject:itemIndexPath])
    {
        // only change attributes on inserted cells
        if (!attributes)
            attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

        // Configure attributes ...
        attributes.alpha = 0.0;
        attributes.center = CGPointMake(_center.x, _center.y);
    }

    return attributes;
}

// Note: name of method changed
// Also this gets called for all visible cells (not just the deleted ones) and
// even gets called when inserting cells!
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    // So far, calling super hasn't been strictly necessary here, but leaving it in
    // for good measure
    UICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];

    if ([self.deleteIndexPaths containsObject:itemIndexPath])
    {
        // only change attributes on deleted cells
        if (!attributes)
            attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

        // Configure attributes ...
        attributes.alpha = 0.0;
        attributes.center = CGPointMake(_center.x, _center.y);
        attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);
    }

    return attributes;
}
于 2013-01-19T19:49:51.267 に答える
12

あなたは一人じゃない。UICollectionViewLayout ヘッダー ファイルのコメントは、物事を少し明確にします。

無効化前の画面上の各要素に対して、finalLayoutAttributesForDisappearingXXX が呼び出され、画面上のものからそれらの最終属性へのアニメーション設定が行われます。

無効化後の画面上の各要素に対して、initialLayoutAttributesForAppearingXXX が呼び出され、これらの初期属性から最終的に画面に表示されるものまでのアニメーション設定が行われます。

基本的finalLayoutAttributesForDisappearingItemAtIndexPathには、アニメーション ブロックの開始前に画面上の各アイテムに対してinitialLayoutAttributesForAppearingItemAtIndexPath呼び出され、アニメーション ブロックの終了後に各アイテムに対して呼び出されます。UICollectionViewUpdateItem送信されたオブジェクトの配列をキャッシュするのはあなたprepareForCollectionViewUpdates次第です。そうすれば、初期属性と最終属性の設定方法がわかります。私の場合、以前のレイアウトの四角形をキャッシュしたprepareLayoutので、使用する正しい初期位置がわかりました。

しばらく困惑したことの 1 つは、super の実装を使用してinitialLayoutAttributesForAppearingItemAtIndexPath、それが返す属性を変更する必要があることです。実装を呼び出しlayoutAttributesForItemAtIndexPathたところ、レイアウトの位置が異なっていたため、アニメーションが機能しませんでした。

于 2012-12-19T21:45:42.627 に答える
-1

Swift 3 で新しいメソッド シグネチャを使用していることを確認してください。このメソッドでは自動修正が機能しません。

func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?
于 2017-01-04T17:01:57.907 に答える