在UICollectionView上动态设置布局会导致无法解释的contentOffset更改 [英] Dynamically setting layout on UICollectionView causes inexplicable contentOffset change

查看:1761
本文介绍了在UICollectionView上动态设置布局会导致无法解释的contentOffset更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据Apple的文档(并在WWDC 2012上吹捧),可以动态设置 UICollectionView 的布局,甚至可以为更改设置动画:

According to Apple's documentation (and touted at WWDC 2012), it is possible to set the layout on UICollectionView dynamically and even animate the changes:


通常在创建集合视图时指定布局对象,但也可以动态更改集合视图的布局。布局对象存储在collectionViewLayout属性中。设置此属性会立即直接更新布局,而无需为更改设置动画。如果要为更改设置动画,则必须调用setCollectionViewLayout:animated:方法。

You normally specify a layout object when creating a collection view but you can also change the layout of a collection view dynamically. The layout object is stored in the collectionViewLayout property. Setting this property directly updates the layout immediately, without animating the changes. If you want to animate the changes, you must call the setCollectionViewLayout:animated: method instead.

然而,在实践中,我已经发现 UICollectionView contentOffset 进行了无法解释甚至无效的更改,导致单元格移动不正确,使得该功能几乎无法使用。为了说明这个问题,我将以下示例代码放在一起,这些代码可以附加到放入故事板的默认集合视图控制器中:

However, in practice, I've found that UICollectionView makes inexplicable and even invalid changes to the contentOffset, causing cells to move incorrectly, making the feature virtually unusable. To illustrate the problem, I put together the following sample code that can be attached to a default collection view controller dropped into a storyboard:

#import <UIKit/UIKit.h>

@interface MyCollectionViewController : UICollectionViewController
@end

@implementation MyCollectionViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"CELL"];
    self.collectionView.collectionViewLayout = [[UICollectionViewFlowLayout alloc] init];
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 1;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath];
    cell.backgroundColor = [UIColor whiteColor];
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"contentOffset=(%f, %f)", self.collectionView.contentOffset.x, self.collectionView.contentOffset.y);
    [self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
    NSLog(@"contentOffset=(%f, %f)", self.collectionView.contentOffset.x, self.collectionView.contentOffset.y);
}

@end

控制器设置默认值 UICollectionViewFlowLayout viewDidLoad 中,并在屏幕上显示单个单元格。选择单元格后,控制器会创建另一个默认 UICollectionViewFlowLayout 并使用动画设置集合视图:YES 旗。预期的行为是细胞不移动。然而,实际的行为是单元格在屏幕外滚动,此时甚至无法在屏幕上滚动单元格。

The controller sets a default UICollectionViewFlowLayout in viewDidLoad and displays a single cell on-screen. When the cells is selected, the controller creates another default UICollectionViewFlowLayout and sets it on the collection view with the animated:YES flag. The expected behavior is that the cell does not move. The actual behavior, however, is that the cell scroll off-screen, at which point it is not even possible to scroll the cell back on-screen.

查看控制台日志显示contentOffset已经莫名其妙地改变了(在我的项目中,从(0,0)到(0,205))。我发布了非解决方案的解决方案 - 动画案例即动画:否),但由于我需要动画,我很有兴趣知道是否有人有动画的解决方案或解决方法case。

Looking at the console log reveals that the contentOffset has inexplicably changed (in my project, from (0, 0) to (0, 205)). I posted a solution for the solution for the non-animated case (i.e. animated:NO), but since I need animation, I'm very interested to know if anyone has a solution or workaround for the animated case.

作为旁注,我测试了自定义布局并获得相同的行为。

As a side-note, I've tested custom layouts and get the same behavior.

推荐答案

我已经把头发拉过来好几天了,并找到了解决我的情况可能会有所帮助的方法。
在我的情况下,我有一个折叠的照片布局,就像在iPad上的照片应用程序。它显示相册顶部的相册,当您点击相册时,它会扩展照片。所以我有两个单独的UICollectionViewLayouts,并在他们之间切换 [self.collectionView setCollectionViewLayout:myLayout animated:YES] 我遇到了你在动画之前跳过的细胞的确切问题并意识到它是 contentOffset 。我用 contentOffset 尝试了一切,但在动画期间它仍然跳了起来。 Tyler的解决方案上面有效,但它仍然在搞乱动画。

I have been pulling my hair out over this for days and have found a solution for my situation that may help. In my case I have a collapsing photo layout like in the photos app on the ipad. It shows albums with the photos on top of each other and when you tap an album it expands the photos. So what I have is two separate UICollectionViewLayouts and am toggling between them with [self.collectionView setCollectionViewLayout:myLayout animated:YES] I was having your exact problem with the cells jumping before animation and realized it was the contentOffset. I tried everything with the contentOffset but it still jumped during animation. tyler's solution above worked but it was still messing with the animation.

然后我注意到它只在屏幕上有几张专辑时才会发生,不足以填满屏幕。我的布局按照建议覆盖 - (CGSize)collectionViewContentSize 。当只有少数专辑时,集合视图的内容大小小于视图内容大小。当我在集合布局之间切换时,这会导致跳转。

Then I noticed that it happens only when there were a few albums on the screen, not enough to fill the screen. My layout overrides -(CGSize)collectionViewContentSize as recommended. When there are only a few albums the collection view content size is less than the views content size. That's causing the jump when I toggle between the collection layouts.

所以我在我的布局上设置了一个名为minHeight的属性,并将其设置为集合视图父级的高度。然后我在返回之前检查高度 - (CGSize)collectionViewContentSize 我确保高度> =最小高度。

So I set a property on my layouts called minHeight and set it to the collection views parent's height. Then I check the height before I return in -(CGSize)collectionViewContentSize I ensure the height is >= the minimum height.

不是真正的解决方案,但它现在正常运作。我会尝试将您的集合视图的 contentSize 设置为至少包含视图的长度。

Not a true solution but it's working fine now. I would try setting the contentSize of your collection view to be at least the length of it's containing view.

编辑:
如果从UICollectionViewFlowLayout继承,Manicaesar添加了一个简单的解决方法:

edit: Manicaesar added an easy workaround if you inherit from UICollectionViewFlowLayout:

-(CGSize)collectionViewContentSize { //Workaround
    CGSize superSize = [super collectionViewContentSize];
    CGRect frame = self.collectionView.frame;
    return CGSizeMake(fmaxf(superSize.width, CGRectGetWidth(frame)), fmaxf(superSize.height, CGRectGetHeight(frame)));
}

这篇关于在UICollectionView上动态设置布局会导致无法解释的contentOffset更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆