调用setCollectionViewLayout:animated不会重新加载UICollectionView

时间:2014-03-18 10:05:21

标签: iphone objective-c uicollectionview

我正在使用带有两个自定义布局的UICollectionView - 这些布局是UICollectionViewFlowLayout

的子类

当我的视图第一次加载时,我使用以下命令将其设置为默认视图:

[self.collectionView setCollectionViewLayout:self.tableViewLayout];

这叫:cellForItemAtIndexPath - 所以没问题。这是viewWillAppear方法。

然后我使用UIButton将布局从当前视图更改为下一个布局,如下所示:

-(void)changeViewLayoutButtonPressed
{
    self.changeLayout = !self.changeLayout;


    if (self.changeLayout){

        [self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];

    }

    else {


        [self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];

    }
}

此调用后 - 调用numberOfItemsInSection。我已在调试器中检查了返回帐户不为零。

在该调用之后,没有其他任何内容被调用,我的UICollectionView更改了布局,但由于未调用cellForItemAtIndexPath - 单元格设置不正确。

如果我将[self.collectionView roloadData]放在numberOfItemsInSection内 - 则调用cellForItemAtIndexPath并设置单元格。

我不需要手动调用来重新加载numberOfItemsInSection中的数据。有人能告诉我发生了什么吗?

修改

我忘了提到我正在为两个不同的单元格使用两个不同的UINib,因为它们需要稍微不同的布局。这会是一个问题吗? 谢谢!

修改2

是的,所以我的工作几乎就像我想要的那样。以下是用于集合视图的所有代码以及我如何更改其布局。

自定义布局

这些是UICollectionViewFlowLayout的子类 - 我子类化的原因仅仅是因为我的UICollectionView需要看起来并且表现得非常接近Apple的预制布局。但是,只是不同的单元格大小。

TableViewLayout - 头文件中没有代码。   - BBTradeFeedTableViewLayout.m

@implementation BBTradeFeedTableViewLayout

-(id)init
{
    self = [super init];

    if (self){

        self.itemSize = CGSizeMake(320, 80);
        self.minimumLineSpacing = 0.1f;
    }

    return self;
}
@end

Gride Layout - 头文件中没有代码。   - BBTradeFeedGridViewLayout.m

   @implementation BBTradeFeedGridViewLayout

-(id)init
{
    self = [super init];

    if (self){

        self.itemSize = CGSizeMake(159, 200);
        self.minimumInteritemSpacing = 0.1f;
        self.minimumLineSpacing = 0.1f;
    }
    return self; 
}
@end

然后在ViewController的{​​{1}}中 - 我声明了两个自定义布局:

UICollectionView

然后我为collectionView注册了两个.xib文件:

@property (strong, nonatomic) BBTradeFeedTableViewLayout *tableViewLayout;
@property (strong, nonatomic) BBTradeFeedGridViewLayout *grideLayout;

然后,我有一个更改布局的UIButton:

  [self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemTableViewCell" bundle:nil] forCellWithReuseIdentifier:@"TableItemCell"];
        [self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemGridViewCell" bundle:nil] forCellWithReuseIdentifier:@"GridItemCell"];

最后 - 当完成Web服务调用时 - 它会调用 -(void)changeViewLayoutButtonPressed { if (!self.gridLayoutActive){ self.gridLayoutActive = YES; [self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES]; self.lastLayoutUsed = @"GridLayout"; } else { self.gridLayoutActive = NO; [self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES]; self.lastLayoutUsed = @"TableLayOut"; } [self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]]; }

所以我的[self.tradeFeedCollectionView reloadData];重新加载,最后一个方法:

UICollectionView

以上代码的问题

以上代码确实有效。然而,细胞没有很好的动画,它看起来很奇怪,几乎就像刷新了一样。这是由于致电:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { static NSString *tableCellIdentifier = @"TableItemCell"; static NSString *gridCellIdentifier = @"GridItemCell"; if (indexPath.item < [self.tradeSearchArray count]){ if (self.gridLayoutActive == NO){ BBItemTableViewCell *tableItemCell = [collectionView dequeueReusableCellWithReuseIdentifier:tableCellIdentifier forIndexPath:indexPath]; if ([self.tradeSearchArray count] > 0){ self.toolBarButtomItem.title = [NSString stringWithFormat:@"%d Results", self.searchResult.searchResults]; tableItemCell.gridView = NO; tableItemCell.backgroundColor = [UIColor whiteColor]; tableItemCell.item = self.tradeSearchArray[indexPath.row]; } return tableItemCell; }else { BBItemTableViewCell *gridItemCell= [collectionView dequeueReusableCellWithReuseIdentifier:gridCellIdentifier forIndexPath:indexPath]; if ([self.tradeSearchArray count] > 0){ self.toolBarButtomItem.title = [NSString stringWithFormat:@"%d Results", self.searchResult.searchResults]; gridItemCell.gridView = YES; gridItemCell.backgroundColor = [UIColor whiteColor]; gridItemCell.item = self.tradeSearchArray[indexPath.row]; } return gridItemCell; }

但这是我能让它接近我想要的唯一方法。

7 个答案:

答案 0 :(得分:20)

-setCollectionViewLayout:-setCollectionViewLayout:animated:不会导致UICollectionView重新加载其数据。

  • 如果您想更改单元格样式或更新数据,请调用[self.collectionView reloadData]UICollectionViewDataSource协议方法。

  • 如果您想将UICollectionView布局更改为其他布局,请致电-setCollectionViewLayout:。或者,如果您要更新UICollectionView布局,只需致电[self.collectionView.collectionViewLayout invalidateLayout]即可。

单元布局和数据是UICollectionView中的两个不同的东西。

<强>更新
你应该丢弃所有陈旧的数据,可能是-reloadData。并为UICollectionViewLayout子类中的每个单元格计算新帧。覆盖- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
您决定新的contentOffset。例如,你可以保留一些可见单元格的indexPath,并决定在你的同一indexPath之后滚动到setContentOffset:frame.origin到新单元格的indexPath。布局改变了。

答案 1 :(得分:16)

只需拨打performBatchUpdates 之前即可切换布局([self.collectionView reloadData]; [self.collectionView.collectionViewLayout invalidateLayout]; [self.collectionView setCollectionViewLayout:yourLayout animated:YES]; 来电不是必需的):

self.collectionView?.reloadData()
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.setCollectionViewLayout(yourLayout, animated: true)

在斯威夫特:

textFile.distinct() // remove all duplicate key;value pairs
    .map( line => line.split(";")(0) ) // extract the keys
    .map( k => (k,1) ) // convert to countable tuples
    .reduceByKey(_+_) // count keys

答案 2 :(得分:1)

您应该在

之前致电[self.tradeFeedCollectionView invalidateLayout];
if (self.changeLayout){
    [self.tradeFeedCollectionView setCollectionViewLayout:self.grideLayout animated:YES];
}
else {
    [self.tradeFeedCollectionView setCollectionViewLayout:self.tableViewLayout animated:YES];
}

答案 3 :(得分:0)

您只需要调用此方法:

[self.collectionView setCollectionViewLayout:layout animated:YES];

我有一个类似的错误,但最终我的单元格子视图没有使用自动布局设置。单元格正确调整大小,但我的子视图不是,因此看起来单元格大小永远不会改变。通过在cell.contentView上设置clipsToBounds = YES,快速在代码中检查这一点。

答案 4 :(得分:0)

如果你想更新布局,这是一个简单的技巧在你更新collectionView的任何地方使用它:

[self.collectionView removeFromSuperview]; //First remove the Collection View

//Relocate the view with layouts
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.minimumInteritemSpacing = 10;
layout.minimumLineSpacing = 10;

 self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.width,100) collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
[self.collectionView reloadData];

[self.view addSubview:self.collectionView];

答案 5 :(得分:0)

(代表问题作者发布解决方案)

我终于找到了一个简单明了的解决方案。

标记的答案是正确的,我需要在我的-reloadData上调用UICollectionView - 但是,当在两个单元格之间切换时,这会破坏动画。

从明确的答案中接受建议后 - 我只是重写了我的'UIButton&#39;方法,改变细胞

我发现如果我打电话:

[self.collectionview performBatchUpdates:^{  } completion:^(BOOL finished) {

}];

根据WDDC视频 - 这可以使用-reloadData方法激活更改:

示例:

[self.collectionView reloadData]; 
    [self.collectionView performBatchUpdates:^{
        [self.collectionView.collectionViewLayout invalidateLayout];
        [self.collectionView setCollectionViewLayout:self.grideLayout animated:YES];
    } completion:^(BOOL finished) {

    }];
}

答案 6 :(得分:0)

我发现能够轻松,漂亮地为两个细胞设置动画。种类和布局同时最好reloadSections(而不是reloadData),然后设置一个带动画的新布局:

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
[self.collectionView setCollectionViewLayout:newLayout animated:animated];