私がやりたいのは、セルが選択されたときにUICollectionViewCellのサイズを変更し、その変更をアニメーション化することです。私はすでに、collectionView: didSelectItemAtIndexPath:
その後、UICollectionViewでreloadData
を呼び出して、選択したセルを異なるサイズで表示します。
それにもかかわらず、これは一度にすべて発生し、サイズの変化をアニメーション化する方法がわかりません。何か案は?
私はすでに 選択時のuicollectionviewセルのアニメーション化 を見つけましたが、答えは私にとって不特定であり、それが私の場合にも役立つかどうかはまだわかりませんでした。
[UIView transitionWithView:collectionView
duration:.5
options:UIViewAnimationOptionTransitionCurlUp
animations:^{
//any animatable attribute here.
cell.frame = CGRectMake(3, 14, 100, 100);
} completion:^(BOOL finished) {
//whatever you want to do upon completion
}];
didselectItemAtIndexPath
メソッド内のそれらの行に沿って何かで遊んでください。
チェイス・ロバーツの助けを借りて、私の問題の解決策を見つけました。私のコードは基本的に次のようになります。
// Prepare for animation
[self.collectionView.collectionViewLayout invalidateLayout];
UICollectionViewCell *__weak cell = [self.collectionView cellForItemAtIndexPath:indexPath]; // Avoid retain cycles
void (^animateChangeWidth)() = ^()
{
CGRect frame = cell.frame;
frame.size = cell.intrinsicContentSize;
cell.frame = frame;
};
// Animate
[UIView transitionWithView:cellToChangeSize duration:0.1f options: UIViewAnimationOptionCurveLinear animations:animateChangeWidth completion:nil];
詳細については:
最も重要なステップの1つは、使用しているUICollectionView.collectionViewLayout
のinvalidateLayout
呼び出しです。忘れてしまうと、コレクションの境界を越えて細胞が成長する可能性が高くなります-これはおそらく起こりたくないことです。また、コードはある時点でレイアウトのセルの新しいサイズを表示する必要があることも考慮してください。私の場合(UICollectionViewFlowLayout
を使用しています)、collectionView:layout:sizeForItemAtIndexPath
メソッドを変更して、変更されたセルの新しいサイズを反映させました。その部分を忘れて、最初にinvalidateLayout
を呼び出してからサイズの変化をアニメーション化しようとしても、セルサイズはまったく変化しません。
最も奇妙な(少なくとも私には)ですが、重要なのは、アニメーションブロック内でinvalidateLayout
notを呼び出すことです。これを行うと、アニメーションは滑らかではなく、グリッチとフリッカーを表示しません。
コレクションビュー全体ではなく、UIView
の引数としてセルを使用してtransitionWithView
s transitionWithView:duration:options:animations:completion:
メソッドを呼び出す必要があります。これは、コレクション全体ではなく、アニメーション化するセルだからです。
セルのintrinsicContentSize
メソッドを使用して必要なサイズを返しました。この場合、セルの選択状態に応じて、セルの幅を拡大または縮小してボタンを表示または非表示にします。
これが一部の人々に役立つことを願っています。私にとっては、そのアニメーションを正しく動作させる方法を見つけるのに数時間かかったので、他の人をその時間のかかる負担から解放しようとします。
セルのサイズのアニメーション化は、テーブルビューの場合と同じようにコレクションビューでも機能します。セルのサイズをアニメーション化する場合は、セルの状態を反映するデータモデルを使用し(私の場合はフラグ(CollectionViewCellExpanded、CollectionViewCellCollapsed)を使用し、それに応じてCGSizeを返します。
呼び出してperformBathUpdatesを空にすると、ビューは自動的にアニメーション化します。
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[collectionView performBatchUpdates:^{
// append your data model to return a larger size for
// cell at this index path
} completion:^(BOOL finished) {
}];
}
-setCollectionViewLayout:animated:
を使用して同じコレクションビューレイアウトの新しいインスタンスを作成することで、変更のアニメーション化に成功しました。
たとえば、UICollectionViewFlowLayout
を使用している場合:
// Make sure that your datasource/delegate are up-to-date first
// Then animate the layout changes
[collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
これは私が見つけた最も簡単な解決策です-魅力のように動作します。アニメーションをスムーズにし、レイアウトを台無しにしません。
Swift
collectionView.performBatchUpdates({}){}
Obj-C
[collectionView performBatchUpdates:^{ } completion:^(BOOL finished) { }];
ブロック(Swiftのクロージャー)は意図的に空にしておく必要があります!
セルサイズをアニメーション化する良い方法は、uicollectionViewCell自体でisSelectedをオーバーライドすることです。
class CollectionViewCell: UICollectionViewCell {
override var isHighlighted: Bool {
didSet {
if isHighlighted {
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: {
self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
}, completion: nil)
} else {
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseOut, animations: {
self.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: nil)
}
}
}
}
PerformBatchUpdatesを使用しても、セルのコンテンツのレイアウトはアニメーション化されません。代わりに、次を使用できます。
collectionView.collectionViewLayout.invalidateLayout()
UIView.animate(
withDuration: 0.4,
delay: 0.0,
usingSpringWithDamping: 1.0,
initialSpringVelocity: 0.0,
options: UIViewAnimationOptions(),
animations: {
self.collectionView.layoutIfNeeded()
},
completion: nil
)
これにより、非常にスムーズなアニメーションが得られます。
これはIgnatius Tremorの答えに似ていますが、トランジションアニメーションが適切に機能しませんでした。
完全なソリューションについては、 https://github.com/cnoon/CollectionViewAnimations を参照してください。
これは私のために働いた。
collectionView.performBatchUpdates({ () -> Void in
let ctx = UICollectionViewFlowLayoutInvalidationContext()
ctx.invalidateFlowLayoutDelegateMetrics = true
self.collectionView!.collectionViewLayout.invalidateLayoutWithContext(ctx)
}) { (_: Bool) -> Void in
}