ios UICollectionView:选择时动画单元格大小的变化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13780153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UICollectionView: Animate cell size change on selection
提问by Ignatius Tremor
What I want to do is change the size of an UICollectionViewCell, and to animate that change, when the cell is selected. I already managed to do that unanimated by marking a cell as selected in collectionView: didSelectItemAtIndexPath:
and then calling reloadData
on my UICollectionView, displaying the selected cell with a different size.
我想要做的是更改 UICollectionViewCell 的大小,并在选择单元格时为该更改设置动画。我已经设法通过将一个单元格标记为已选中collectionView: didSelectItemAtIndexPath:
然后调用reloadData
我的 UICollectionView 来以不同的大小显示选定的单元格来做到这一点。
Nevertheless, this happens all at once, and I have no clue how to get that change in size animated. Any ideas?
尽管如此,这一切都是一次性发生的,我不知道如何使大小的变化动画化。有任何想法吗?
I already found Animate uicollectionview cells on selection, but the answer was to unspecific for me and I didn't figure out yet if it could also help me in my case.
我已经在 selection 上找到了Animate uicollectionview 单元格,但答案对我来说是不具体的,我还没有弄清楚它是否也可以帮助我。
采纳答案by Chase Roberts
[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
}];
Play around with something along those lines inside your didselectItemAtIndexPath
method.
在你的didselectItemAtIndexPath
方法中沿着这些线玩一些东西。
回答by Ignatius Tremor
With the help of Chase Roberts, I now found the solution to my problem. My code basically looks like this:
在 Chase Roberts 的帮助下,我现在找到了解决问题的方法。我的代码基本上是这样的:
// 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];
For further explanation:
进一步解释:
One of the most important step is the
invalidateLayout
call on theUICollectionView.collectionViewLayout
you are using. If you forget it, it is likely to happen that cells will grow over the borders of your collection - that's something you most probably don't want to happen. Also consider that your code should at some point present the new size of your cell to your layout. In my case (I'm using anUICollectionViewFlowLayout
), I adjusted thecollectionView:layout:sizeForItemAtIndexPath
method to reflect the new size of the modified cell. Forgetting that part, nothing will happen to your cell sizes at all if you first callinvalidateLayout
and then try to animate the change in size.Most strange (at least to me) but important is that you call
invalidateLayout
notinside the animation block. If you do so, the animation won't display smooth but glitchy and flickering.You have to call
UIView
stransitionWithView:duration:options:animations:completion:
method with the cell as argument fortransitionWithView
, not the whole collection view, because it's the cell you want to get animated, not the entire collection.I used the
intrinsicContentSize
method of my cell to return the size I want - in my case, I grow and shrink the width of the cell to either display a button or hide it, depending on the selection state of the cell.
最重要的步骤之一是
invalidateLayout
调用UICollectionView.collectionViewLayout
您正在使用的。如果您忘记了它,细胞很可能会越过您的集合的边界生长——这是您很可能不希望发生的事情。还要考虑到您的代码应该在某个时候将单元格的新大小呈现给您的布局。在我的情况下(我使用的是UICollectionViewFlowLayout
),我调整了collectionView:layout:sizeForItemAtIndexPath
方法以反映修改后的单元格的新大小。忘记那部分,如果您首先调用invalidateLayout
然后尝试为大小变化设置动画,那么您的单元格大小根本不会发生任何变化。最奇怪(至少对我而言)但重要的是你
invalidateLayout
不在动画块内调用。如果这样做,动画将不会显示平滑,而是会出现故障和闪烁。您必须使用单元格作为参数调用
UIView
stransitionWithView:duration:options:animations:completion:
方法transitionWithView
,而不是整个集合视图,因为它是您想要动画的单元格,而不是整个集合。我使用
intrinsicContentSize
我的单元格的方法返回我想要的大小 - 在我的例子中,我增加和缩小单元格的宽度以显示按钮或隐藏它,具体取决于单元格的选择状态。
I hope this will help some people. For me it took several hours to figure out how to make that animation work correctly, so I try to free others from that time-consuming burden.
我希望这会帮助一些人。对我来说,弄清楚如何让动画正常工作需要几个小时,所以我试图让其他人摆脱这种耗时的负担。
回答by Andy Poes
Animating the size of a cell works the same way for collection views as it does for table views. If you want to animate the size of a cell, have a data model that reflects the state of the cell (in my case, I just use a flag (CollectionViewCellExpanded, CollectionViewCellCollapsed) and return a CGSize accordingly.
动画单元格的大小对于集合视图和表格视图的工作方式相同。如果要为单元格的大小设置动画,请使用反映单元格状态的数据模型(在我的情况下,我只使用一个标志(CollectionViewCellExpanded、CollectionViewCellCollapsed)并相应地返回一个 CGSize。
When you call and empty performBathUpdates call, the view animates automatically.
当您调用并清空 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) {
}];
}
回答by codeperson
I've had success animating changes by using -setCollectionViewLayout:animated:
to create a new instance of the same collection view layout.
通过使用-setCollectionViewLayout:animated:
创建相同集合视图布局的新实例,我成功地对更改进行了动画处理。
For example, if you're using a UICollectionViewFlowLayout
, then:
例如,如果您使用的是 a UICollectionViewFlowLayout
,则:
// Make sure that your datasource/delegate are up-to-date first
// Then animate the layout changes
[collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
回答by Pavel Gurov
This is the simplest solution I have found - works like a charm. Smooth animation, and does not mess up the layout.
这是我找到的最简单的解决方案 - 就像一个魅力。流畅的动画,不会弄乱布局。
Swift
迅速
collectionView.performBatchUpdates({}){}
Obj-C
对象-C
[collectionView performBatchUpdates:^{ } completion:^(BOOL finished) { }];
The blocks (closures in Swift) should be intentionally left empty!
这些块(Swift 中的闭包)应该有意留空!
回答by Cristian Pena
A good way to animate the cell size is to override isSelected in the collectionViewCell itself.
为单元格大小设置动画的一个好方法是覆盖 collectionViewCell 本身中的 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)
}
}
}
}
回答by phatmann
Using performBatchUpdates will not animate the layout of the cell contents. Instead, you can use the following:
使用 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
)
This gives a very smooth animation.
这提供了非常流畅的动画。
This is similar to Ignatius Tremor's answer, but the transition animation did not work properly for me.
这类似于 Ignatius Tremor 的回答,但过渡动画对我来说没有正常工作。
See https://github.com/cnoon/CollectionViewAnimationsfor a complete solution.
有关完整解决方案,请参阅https://github.com/cnoon/CollectionViewAnimations。
回答by Eonil
This worked for me.
这对我有用。
collectionView.performBatchUpdates({ () -> Void in
let ctx = UICollectionViewFlowLayoutInvalidationContext()
ctx.invalidateFlowLayoutDelegateMetrics = true
self.collectionView!.collectionViewLayout.invalidateLayoutWithContext(ctx)
}) { (_: Bool) -> Void in
}
回答by Alexander
class CollectionViewCell: UICollectionViewCell {
override var isHighlighted: Bool {
if isHighlighted {
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut, animations: {
self.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
}) { (bool) in
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut, animations: {
self.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: nil)
}
}
}
}
One just needs to check if the isHighlighted variable was changed to true, then use UIView animation and animate back in the completion handler.
只需检查 isHighlighted 变量是否已更改为 true,然后使用 UIView 动画并在完成处理程序中设置动画。