调整 UICollectionViewCells 的大小以始终填充 UICollectionView

Posted

技术标签:

【中文标题】调整 UICollectionViewCells 的大小以始终填充 UICollectionView【英文标题】:Resize UICollectionViewCells to always fill UICollectionView 【发布时间】:2014-10-01 13:10:17 【问题描述】:

我有一个水平滚动的 UICollectionView,其 UICollectionViewCells 与集合视图本身一样高,三分之一宽(因此一次适合三个)。集合视图是分页的,并使用默认的流布局。

单元格来自 .xib 文件并使用自动布局来保持内容到位。

我想要做的是让集合视图的高度在两个预定义的高度之间切换,并让单元格的高度始终填满可用空间,即使在动画期间也是如此。

collection view 动画是通过像这样对其 superview 的顶部约束进行动画处理来完成的,并且似乎可以工作:

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.

我已经进行了大量研究,但我发现的所有内容都涉及自定义布局或在不同布局之间切换,我认为这不适用于我,因为即使集合视图的高度发生变化,布局也使用相同的逻辑来定位元素。

有什么想法吗?

谢谢!

【问题讨论】:

【参考方案1】:

我认为这可以通过在动画之前更改单元格的 itemSize 来实现。单元格的原始大小设置为如下所示的相同值,但没有 +sign*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];
    

【讨论】:

谢谢!但是,这确实有效,因为您说它并不完美,因为仍然存在褪色。我想知道使用自定义布局是否会改变这一点。我想我在某处读到褪色是 Flow 布局特有的东西...... @LorTush,我想我找到了使用计时器的更好方法。 谢谢,我会试一试。我也会将其标记为正确答案,因为我认为这是我们在不使用自定义布局的情况下所能做到的最好的。 高度动画完成后,可以调用collectionView.reload()。

以上是关于调整 UICollectionViewCells 的大小以始终填充 UICollectionView的主要内容,如果未能解决你的问题,请参考以下文章

如何使 UICollectionViewCells 具有圆角和阴影?

放大二维 UICollectionView

调整包含 UITextView 的 UICollectionViewCell 以适合 contentSize

如何根据 UITableViewCell 中的内容调整水平 UICollectionView 的高度

将 UIKit Dynamics 添加到 UICollectionViewCells 的正确方法是啥?

在横向上消失的 UICollectionViewCells