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

Rob*_*egg 20 iphone objective-c uicollectionview

我正在使用带有两个自定义布局的UICollectionView - 它们是子类 UICollectionViewFlowLayout

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

[self.collectionView setCollectionViewLayout:self.tableViewLayout];
Run Code Online (Sandbox Code Playgroud)

这叫: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];

    }
}
Run Code Online (Sandbox Code Playgroud)

在此呼叫之后 - 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

然后在ViewController我的UICollectionView- 我声明两个自定义布局,如下所示:

@property (strong, nonatomic) BBTradeFeedTableViewLayout *tableViewLayout;
@property (strong, nonatomic) BBTradeFeedGridViewLayout *grideLayout;
Run Code Online (Sandbox Code Playgroud)

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

  [self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemTableViewCell" bundle:nil] forCellWithReuseIdentifier:@"TableItemCell"];
        [self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemGridViewCell" bundle:nil] forCellWithReuseIdentifier:@"GridItemCell"];
Run Code Online (Sandbox Code Playgroud)

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

    -(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]];

}
Run Code Online (Sandbox Code Playgroud)

最后 - 当Web服务调用完成时 - 它调用 [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;
    }
Run Code Online (Sandbox Code Playgroud)

上面代码的问题

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

[self.tradeFeedCollectionView reloadItemsAtIndexPaths:[self.tradeFeedCollectionView indexPathsForVisibleItems]];

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

liu*_*ong 21

-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并决定滚动到indexPathsetContentOffset:frame.origin同一新小区indexPath后,你的布局改变.


Art*_*eyn 16

reloadData 切换布局之前简单地打电话(performBatchUpdates呼叫不是强制性的):

[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView setCollectionViewLayout:yourLayout animated:YES];
Run Code Online (Sandbox Code Playgroud)

在Swift中:

self.collectionView?.reloadData()
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.setCollectionViewLayout(yourLayout, animated: true)
Run Code Online (Sandbox Code Playgroud)