我正在使用带有两个自定义布局的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;
}
但这是我能让它接近我想要的唯一方法。
答案 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];