gpt4 book ai didi

ios - 完善 UICollectionView 布局转换中的 subview 大小调整

转载 作者:技术小花猫 更新时间:2023-10-29 10:42:30 32 4
gpt4 key购买 nike

我正在开发一个具有 UICollectionView 的应用程序 - Collection View 的工作是显示来自网络服务的数据。

我正在尝试实现的应用程序的一个功能是使用户能够将此 UICollectionView 的布局从 GridView 更改为表格 View 。

我花了很多时间来完善它,并设法让它发挥作用。但是,存在一些问题。两种布局之间的过渡看起来不太好,有时它会在切换 View 之间中断,我的应用程序会留下一个处于意外状态的 View 。只有当用户连续快速地在网格和表格 View 之间切换(按 changeLayoutButton)时才会发生这种情况。

所以,显然存在一些问题,我觉得代码有点脆弱。我还需要解决上述问题。

我将从如何实现此 View 开始。

实现

因为我需要两个不同的单元格(grideCelltableViewCell)来显示不同的东西 - 我决定子类化 UICollectionViewFlowLayout 会更好因为它完成了我需要的一切——我需要做的就是更改单元格大小。

考虑到这一点,我创建了两个子类 UICollectionViewFlowLayout

这是这两个类的样子:

BBTradeFeedTableViewLayout.m

    #import "BBTradeFeedTableViewLayout.h"

@implementation BBTradeFeedTableViewLayout

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

if (self){

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

return self;
}

@end

BBTradeFeedGridViewLayout.m

#import "BBTradeFeedGridViewLayout.h"

@implementation BBTradeFeedGridViewLayout

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

if (self){

self.itemSize = CGSizeMake(159, 200);
self.minimumInteritemSpacing = 2;
self.minimumLineSpacing = 3;
}
return self;
}

@end

如您所见,非常简单 - 只需更改单元格大小。

然后在我的 viewControllerA 类中,我像这样实现了 UICollectionView:创建属性:

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

viewDidLoad

/* Register the cells that need to be loaded for the layouts used */
[self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemTableViewCell" bundle:nil] forCellWithReuseIdentifier:@"TableItemCell"];
[self.tradeFeedCollectionView registerNib:[UINib nibWithNibName:@"BBItemGridViewCell" bundle:nil] forCellWithReuseIdentifier:@"GridItemCell"];

用户点击按钮在布局之间切换:

-(void)changeViewLayoutButtonPressed

我使用 BOOL 来确定哪个布局当前处于事件状态,并基于此我使用以下代码进行切换:

[self.collectionView performBatchUpdates:^{

[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView setCollectionViewLayout:self.grideLayout animated:YES];

} completion:^(BOOL finished) {
}];

cellForItemAtIndexPath

我确定我应该使用哪些单元格(网格或 tableView)并加载数据 - 该代码如下所示:

if (self.gridLayoutActive == NO){

self.switchToTableLayout = NO;
BBItemTableViewCell *tableItemCell = [collectionView dequeueReusableCellWithReuseIdentifier:tableCellIdentifier forIndexPath:indexPath];

if ([self.searchArray count] > 0){

self.switchToTableLayout = NO;

tableItemCell.gridView = NO;
tableItemCell.backgroundColor = [UIColor whiteColor];
tableItemCell.item = self.searchArray[indexPath.row];

}
return tableItemCell;
}else

{

BBItemTableViewCell *gridItemCell= [collectionView dequeueReusableCellWithReuseIdentifier:gridCellIdentifier forIndexPath:indexPath];

if ([self.searchArray count] > 0){

self.switchToTableLayout = YES;

gridItemCell.gridView = YES;
gridItemCell.backgroundColor = [UIColor whiteColor];
gridItemCell.item = self.searchArray[indexPath.row];

}

return gridItemCell;
}

最后在两个单元格类中 - 我只是根据需要使用数据来设置图像/文本。

同样在网格单元格中——图像更大,我删除了我不想要的文本——这是使用两个单元格的主要原因。

我对如何使此 View 在 UI 中看起来更流畅且错误更少感兴趣。我想要的外观就像 eBays iOS 应用程序一样——它们在三种不同的 View 之间切换。我只需要在两个不同的 View 之间切换。

最佳答案

@jrturton 的回答很有帮助,但是除非我遗漏了某些东西,否则它确实会使非常简单的事情变得过于复杂。我将从我们同意的要点开始......

在更改布局时防止交互

首先,我同意在布局转换开始时禁用用户交互并在结束时(在完成 block 中)使用 [[UIApplication sharedApplication] begin/endIgnoringInteractionEvents] 重新启用的方法- 这比尝试取消正在进行的过渡动画并立即从当前状态开始反向过渡要好得多。

使用单个单元格类简化布局转换

此外,我非常同意为每个布局使用相同单元格类的建议。在 viewDidLoad 中注册一个单元格类,并简化您的 collectionView:cellForItemAtIndexPath: 方法以仅出列一个单元格并设置其数据:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
BBItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
if ([self.searchArray count] > 0) {
cell.backgroundColor = [UIColor whiteColor];
cell.item = self.searchArray[indexPath.row];
}
return cell;
}

(请注意,单元格本身(除了特殊情况外)不应该知道与当前正在使用的布局、布局是否正在过渡或当前过渡进度有关的任何事情)

然后当您调用 setCollectionViewLayout:animated:completion: 时, Collection View 不需要重新加载任何新的单元格,它只是设置一个动画 block 来更改每个单元格的布局属性(您不需要不需要从 performBatchUpdates: block 中调用此方法,也不需要手动使布局无效)。

动画单元格 subview

但是正如所指出的,您会注意到单元格的 subview 会立即跳转到它们新布局的框架。解决方案是在更新布局属性时简单地强制立即布局单元格 subview :

- (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
[super applyLayoutAttributes:layoutAttributes];
[self layoutIfNeeded];
}

(无需为过渡创建特殊的布局属性)

为什么会这样?当 Collection View 更改布局时,applyLayoutAttributes: 会为每个单元格调用,因为 Collection View 正在为该转换设置动画 block 。但是单元格 subview 的布局并没有立即完成——它被推迟到稍后的运行循环——导致实际的 subview 布局更改没有被合并到动画 block 中,所以 subview 立即跳转到它们的最终位置。调用 layoutIfNeeded 意味着我们告诉单元格我们希望 subview 布局立即发生,所以布局是在动画 block 内完成的, subview 的帧是动画的连同细胞本身。

的确,使用标准的 setCollectionViewLayout:... API 确实会限制对动画时间的控制。如果你想应用自定义缓动动画曲线,那么解决方案如 TLLayoutTransitioning演示一种利用交互式 UICollectionViewTransitionLayout 对象来控制动画时间的简便方法。但是,只要只需要 subview 的线性动画,我认为大多数人都会对默认动画感到满意,尤其是考虑到实现它的单行简单性。

郑重声明,我本人并不热衷于缺乏对动画的控制,因此实现了类似于 TLLayoutTransitioning 的东西。如果这也适用于你,那么请忽略我对@jrturton 的严厉批评,否则他的回答会很好,并查看使用计时器实现的TLLayoutTransitioningUICollectionViewTransitionLayout:)

关于ios - 完善 UICollectionView 布局转换中的 subview 大小调整,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23564453/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com