我有一个水平滚动的UICollectionView,UICollectionViewCells和集合视图本身一样高,第三个宽(所以一次三个)。集合视图已分页并使用默认的Flow Layout。
单元格来自.xib文件,并使用“自动布局”将内容保留在原位。
我想要做的是让集合视图的高度在两个预定义高度之间切换,并且单元格的高度始终填充可用空间,即使在动画期间也是如此。
集合视图动画是通过将顶部约束设置为其超级视图来完成的,并且似乎有效:
UIView.animateWithDuration(0.5, animations: { () -> Void in
self.collectionViewTopConstraint.constant = (self.collectionViewTopConstraint.constant == 50 ? 100 : 50)
self.view.layoutIfNeeded()
})
然而,这使细胞保持不变。
我尝试在动画块的末尾添加以下内容:
self.collectionView.performBatchUpdates({ () -> Void in
}, completion: nil)
这几乎可以工作,但是细胞从一个高度交叉淡化到另一个高度,而不是仅仅改变高度,这看起来很糟糕。
我也尝试了以下内容:
self.collectionView.collectionViewLayout.invalidateLayout()
这可以达到同样的效果,但不是那么顺利。
此外,在这两种情况下,如果重复调用切换动画,我会收到此警告:
the behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less than the height of the UICollectionView minus the section insets top and bottom values.
我做了很多研究,但我发现的一切都涉及自定义布局或在不同布局之间切换,我认为这些不适用于我,因为即使集合视图的高度发生变化,布局也使用相同的逻辑来定位元件。
有什么想法吗?
谢谢!
答案 0 :(得分:1)
我认为这可以通过在动画之前更改单元格的itemSize来实现。单元格的原始大小设置为如下所示的相同值,但没有+号* 50术语。
- (IBAction)toggleCollectionViewSize:(id)sender {
self.collectionViewTopConstraint.constant = (self.collectionViewTopConstraint.constant == 50)? 100 : 50;
NSInteger sign = (self.collectionViewTopConstraint.constant == 50)? 1 : -1;
self.layout.itemSize = CGSizeMake(self.collectionView.frame.size.width/3.0 , self.collectionView.frame.size.height + sign*50);
[UIView animateWithDuration:.5 animations:^{
[self.view layoutIfNeeded];
}];
}
我在顶部,中部和底部有视图的单元格上测试了这个。它看起来很不错,但底部视图有轻微的移动,我无法解释。当转换发生时,您仍然会对单元格略微褪色(其alpha值降低)。如果集合视图背景颜色与单元格背景颜色相同,则可以最小化此视觉效果。
编辑后:
如果使用计时器而不是animateWithDuration,效果会更好;我不会那样褪色。
-(void)viewWillLayoutSubviews {
self.layout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/3.0 , self.collectionView.bounds.size.height - 1); // the -1 suppresses a warning about the height that you get on every toggle. I still get one warning at the start.
}
- (IBAction)toggleCollectionViewSize:(id)sender {
NSInteger sign = (self.topCon.constant == 50)? 1 : -1;
[NSTimer scheduledTimerWithTimeInterval:.01 target:self selector:@selector(shrink:) userInfo:@(sign) repeats:YES];
}
-(void)shrink:(NSTimer *) aTimer {
NSInteger sign = [aTimer.userInfo integerValue];
self.topCon.constant += sign;
if (self.topCon.constant == 100 || self.topCon.constant == 50) {
[aTimer invalidate];
}
}