根据苹果公司的文档(并在2012年WWDC大会上被吹捧),可以动态地将布局设置为UICollectionView,甚至可以将更改设置为动画:

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

然而,在实践中,我发现UICollectionViewcontentOffset做出了令人费解甚至无效的更改,导致细胞移动不正确,使得该功能实际上无法使用.为了说明这个问题,我将以下示例代码组合在一起,这些代码可以附加到拖放到情节提要中的默认集合视图控制器上:

#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

控制器在viewDidLoad中设置默认值UICollectionViewFlowLayout,并在屏幕上显示单个单元格.当单元格被选中时,控制器创建另一个默认值UICollectionViewFlowLayout,并在集合视图上用animated:YES标志设置它.预期的行为是单元格不移动.然而,实际行为是单元格滚动到屏幕外,此时甚至不可能将单元格滚动回屏幕上.

查看控制台日志(log)会发现contentOffset莫名其妙地发生了更改(在我的项目中,从(0,0)更改为(0,205)).我发布了solution for the non-animated case(i.e. animated:NO)的解决方案,但由于我需要动画,我非常想知道是否有人有动画 case 的解决方案或变通方法.

顺便说一句,我测试了自定义布局,并获得了相同的行为.

推荐答案

这几天来,我一直在为这个问题绞尽脑汁,并为我的处境找到了一个可能会有所帮助的解决方案.

然后我注意到,只有当屏幕上只有几张专辑时,才会出现这种情况,而这还不足以填满屏幕.我的布局覆盖了推荐的-(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.

这不是一个真正的解决方案,但现在运行得很好.我会try 将您的集合视图的contentSize至少设置为其包含视图的长度.

edit:

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

Ios相关问答推荐

在Swift5中,将某些属性值从一个类复制到另一个类实例

如何通过S定义的对象设置删除基于块的观察者的测试?

如何在SwiftUI中顺时针和逆时针两个方向应用旋转效果?

无法向委托发送数据

SwiftUI - 搜索栏和导航标题之间的空间太大

封装 Swift 导入

iOS上从谷歌云存储API不断收到网络连接已丢失的错误信息

UIView 阴影不适用于自定义扩展

发生异常:需要 issuerId

叠加视图不在堆栈中维护自身 - SwiftUI

Flutter:无法构建 iOS 应用程序ARCHIVE FAILED,为设备归档时遇到错误

检测 iPhone 应用程序中是否存在摄像头?

快速禁用 UITextfield 的用户输入

在 Swift 中追加字符串

iOS WKWebView 不显示 javascript alert() 对话框

如何像在 Facebook 应用程序中一样以编程方式打开设置?

正确的领域使用模式/最佳实践?

如何关闭 iOS 键盘?

测试目标 X 遇到错误(提前意外退出,操作从未完成 bootstrap - 不会try 重新启动

Parse for iOS:try 运行应用程序时出错