41

次の 2 つの関数を使用して CollectionView にセルを挿入および削除するときにセルの属性を調整するカスタム フロー レイアウトがありますが、デフォルトのアニメーション期間を調整する方法がわかりません。

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
    UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

    // Assign the new layout attributes
    attributes.transform3D = CATransform3DMakeScale(0.5, 0.5, 0.5);
    attributes.alpha = 0;

    return attributes;
}

- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {

    UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];

    // Assign the new layout attributes
    attributes.transform3D = CATransform3DMakeScale(0.5, 0.5, 0.5);
    attributes.alpha = 0;

    return attributes;
}
4

9 に答える 9

5

試行錯誤[CATransaction setAnimationDuration:]した後[UIView setAnimationDuration:]、レイアウト プロセスのすべての段階で成功UICollectionViewせずに、プライベート API に依存せずに作成されたセル アニメーションの期間を変更するややハックな方法を見つけました。

CALayerのプロパティを使用speedして、特定のレイヤーで実行されるアニメーションの相対的なメディア タイミングを変更できます。これを で機能させるには、セルのレイヤーで 1 未満にUICollectionView変更できます。layer.speed明らかに、セルのレイヤーのアニメーション速度が常に統一されていないのは良くないので、1 つのオプションはNSNotification、セルがサブスクライブするセル アニメーションの準備時に をディスパッチして、レイヤーの速度を変更し、それを元に戻すことです。アニメーションが終了した後の適切な時間。

このアプローチはかなり遠回りなので、長期的な解決策として使用することはお勧めしませんが、うまくいきます。今後、Apple が UICollectionView アニメーションのオプションをさらに公開してくれることを願っています。

于 2013-08-12T20:59:18.577 に答える
4

レイヤーの速度プロパティを設定して(Rotoava's Answer のように)、コントロールのアニメーション速度を変更できます。問題は、挿入アニメーションの実際の長さが分からないため、任意の値を使用していることです。

この投稿を使用すると、デフォルトのアニメーションの長さを把握できます。

newAnimationDuration = (1/layer.speed)*originalAnimationDuration
layer.speed = originalAnimationDuration/newAnimationDuration

アニメーションの長さを 400 ミリ秒にしたい場合は、レイアウトで次のようにします。

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes* attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:indexPath];
    //set attributes here
    UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
    CGFloat originalAnimationDuration = [CATransaction animationDuration];
    CGFloat newAnimationDuration = 0.4f;
    cell.layer.speed = originalAnimationDuration/newAnimationDuration;
    return attributes;
}

私の場合、画面外にドラッグできるセルがあり、パン ジェスチャの速度に基づいて削除アニメーションの期間を変更したいと考えていました。

ジェスチャ レコグナイザー (コレクション ビューの一部である必要があります) で:

- (void)handlePanGesture:(UIPanGestureRecognizer *)sender
{
    CGPoint dragVelocityVector = [sender velocityInView:self.collectionView];
    CGFloat dragVelocity = sqrt(dragVelocityVector.x*dragVelocityVector.x + dragVelocityVector.y*dragVelocityVector.y);
    switch (sender.state) {
    ...
    case UIGestureRecognizerStateChanged:{
        CustomLayoutClass *layout = (CustomLayoutClass *)self.collectionViewLayout;
        layout.dragSpeed = fabs(dragVelocity);
    ...
    }
    ...
}

次に、customLayout で:

- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes* attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:indexPath];
    CGFloat animationDistance = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
    CGFloat originalAnimationDuration = [CATransaction animationDuration];
    CGFloat newAnimationDuration = animationDistance/self.dragSpeed;
    UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
    cell.layer.speed = originalAnimationDuration/newAnimationDuration;
    return attributes;
}
于 2015-09-14T19:26:41.123 に答える
4

UICollectionViewハードコードされた値を使用して、すべてのアニメーションを内部的に開始します。ただし、アニメーションがコミットされるまでは、いつでもその値をオーバーライドできます。一般に、プロセスは次のようになります。

  • アニメーションを開始する
  • すべてのレイアウト属性を取得する
  • ビューに属性を適用する (UICollectionViewCell の)
  • アニメーションをコミットする

属性の適用は各 UICollectionViewCell の下で行われ、適切なメソッドで animationDuration をオーバーライドできます。問題は、UICollectionViewCell にパブリック メソッドがあるが、applyLayoutAttributes:デフォルトの実装が空であることです。基本的に、UICollectionViewCell には別のプライベート メソッドが呼び出され_setLayoutAttributes:、このプライベート メソッドは UICollectionView によって呼び出され、このプライベート メソッドはapplyLayoutAttributes:最後に呼び出されます。フレーム、位置、変換などのデフォルトのレイアウト属性は、呼び出されるanimationDuration前に current に適用されます。applyLayoutAttributes:そうは言ってもanimationDuration、プライベートメソッドでオーバーライドする必要があります_setLayoutAttributes:

- (void) _setLayoutAttributes:(PSTCollectionViewLayoutAttributes *)layoutAttributes
{
    [UIView setAnimationDuration:3.0];
    [super _setLayoutAttributes:layoutAttributes];
}

これは明らかに、applestore-safe ではありません。これらのランタイム ハックの 1 つを使用して、このプライベート メソッドを安全にオーバーライドできます。

于 2013-02-28T21:35:16.090 に答える
1

forBaselineLayout が廃止されたため、@AshleyMills への更新

これは機能します

self.collectionView.performBatchUpdates({ () -> Void in
    let indexSet = IndexSet(0...(numberOfSections - 1))
    self.collectionView.insertSections(indexSet)
    self.collectionView.forFirstBaselineLayout.layer.speed = 0.5
}, completion: { (finished) -> Void in
    self.collectionView.forFirstBaselineLayout.layer.speed = 1.0
})
于 2017-08-09T13:30:51.697 に答える