UICollectionView 不会在屏幕旋转时更新其布局

Posted

技术标签:

【中文标题】UICollectionView 不会在屏幕旋转时更新其布局【英文标题】:UICollectionView Will Not Update Its Layout On Screen Rotation 【发布时间】:2018-02-15 19:41:34 【问题描述】:

我有一个自定义的UIView 和一个UICollectionView

在屏幕旋转时,我试图让UICollectionView 在屏幕上伸展,然后重绘其单元格。

下载数据后,我尝试了[grid setNeedsLayout][grid setNeedsDisplay],但都没有成功。

这就是我想要发生的事情:

肖像

风景

(这也是应用以横向启动时的显示方式,但如果您更改为纵向,它不会更新。)

但是如果我从Portrait 模式开始并切换到Landscape,这就是我得到的。

我正在以编程方式创建这些视图。我没有使用任何情节提要。

我试过了:

-(void)viewDidLayoutSubviews 
    grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];


我也试过玩弄:

- (void) viewWillLayoutSubviews 

    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];

    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
    
        //LANDSCAPE
        if(grid)
            NSLog(@"Grid Needs Landscape Layout");
            grid.frame =CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
            [grid refreshData];
        

    else 
        //PORTRIAT
        if(grid)
            NSLog(@"Grid Needs Portrait Layout");
            grid.frame =CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
            [grid refreshData];
        
    

但我无法拉伸。

有什么帮助吗?

MyThumbnailGridView

@interface ViewController () <UINavigationControllerDelegate> 

    MyThumbnailGridView *grid;

    NSMutableArray * arrImages;


- (void)viewDidLoad 
    [super viewDidLoad];

    arrImages = [NSMutableArray new];

    grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
    //grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectZero];
    NSLog(@"showThumbnailGrid Grid View Size: %@", NSStringFromCGRect(grid.frame));

    [self.view addSubview:grid];

    [self getListOfImages];



-(void) getListOfImages 
        //Do background task to get images  and fill arrImages
         [self onDownloadImageDataComplete];    



- (void) onDownloadImageDataComplete
    grid.imageDataSource = arrImages;
    //  [grid setNeedsLayout];
    //  [grid setNeedsDisplay];


//...
@end

*MyThumbnailGridView.h

@interface MyThumbnailGridView : UIView

-(id)initWithFrame:(CGRect)frame;
-(void) refreshData;

@property (nonatomic,strong) NSArray *imageDataSource;

@end

*MyThumbnailGridView.m

@interface MyThumbnailGridView () <UICollectionViewDelegate, UICollectionViewDataSource>
    UICollectionView *collectionView;


@end

@implementation MyThumbnailGridView


- (instancetype) initWithFrame:(CGRect)frame 
    self = [super initWithFrame:frame];
    if(self)
        [self customInit];

    
    return self;

- (void) customInit 
    collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:[[MyFlowLayout alloc] init]];
    collectionView.delegate = self;
    collectionView.dataSource = self;
    collectionView.allowsMultipleSelection = NO;
    collectionView.showsVerticalScrollIndicator = YES;
    [collectionView setBackgroundColor:[UIColor darkGrayColor]];
    [collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"MyId"];
    [self addSubview:collectionView];

- (void) refreshData 
    NSLog(@"Refresh Grid Data");
    [collectionView reloadData];


////other code
@end

MyFlowLayout

@interface MyFlowLayout : UICollectionViewFlowLayout
@end

@implementation MyFlowLayout
- (instancetype)init
    self = [super init];
    if (self)
    
        self.minimumLineSpacing = 1.0;
        self.minimumInteritemSpacing = 1.0;
        self.scrollDirection = UICollectionViewScrollDirectionVertical;

    
    return self;


- (CGSize)itemSize 
    NSInteger numberOfColumns = 3;
    CGFloat itemWidth = (CGRectGetWidth(self.collectionView.frame) - (numberOfColumns - 1)) / numberOfColumns;
    return CGSizeMake(itemWidth, itemWidth);


@end

MyCollectionViewCell

@interface MyCollectionViewCell : UICollectionViewCell
@property (strong, nonatomic)  UIImageView *imageView;
@end
@implementation MyCollectionViewCell

- (instancetype)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 

        self.imageView = [UIImageView new];
        [self.imageView setContentMode:UIViewContentModeScaleAspectFill];
        [self.imageView setClipsToBounds:YES];
        [self.imageView setBackgroundColor:[UIColor darkGrayColor]];
        [self.contentView addSubview:self.imageView];

    
    return self;


- (void)prepareForReuse 
    [super prepareForReuse];
    self.imageView.image = nil;
    [self.imageView setHidden:NO];


- (void)layoutSubviews 
    [super layoutSubviews];
    [self.imageView setFrame:self.contentView.bounds];

@end

【问题讨论】:

您可以尝试将viewWillLayoutSubviews 中的所有内容放入viewDidLayoutSubviews,然后在该方法中先调用super.viewDidLayoutSubviews() 吗? 刚刚在 ViewController 中尝试过,没有用。 您应该使集合视图上的布局无效 @user-44651 你在第一行打过[super viewDidLayoutSubviews];吗? 【参考方案1】:

这可以解决 您可以在方向的委托函数中更改MyThumbnailGridView 视图的框架,或者使用这样的约束创建视图

(void)viewDidLoad 

   [super viewDidLoad];

    arrImages = [NSMutableArray new];

    grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];

    [self.view addSubview:grid];    

    [self getListOfImages];

 

-(void)viewDidLayoutSubviews
  
   if(Once)

        Once = NO;

       // adding constraints

  MyThumbnailGridView.translatesAutoresizingMaskIntoConstraints = NO;

  [self.MyThumbnailGridView.widthAnchor constraintEqualToConstant:self.view.frame.size.width].active = YES;

  [self.MyThumbnailGridView.heightAnchor constraintEqualToConstant:self.view.frame.size.height/2].active = YES;

  [self.MyThumbnailGridView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;

  [self.MyThumbnailGridView.topAnchor  constraintEqualToAnchor:self.view.topAnchor constant:self.view.frame.size.height/2].active = YES;



    

也实现这个

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator

    [self.view layoutIfNeeded];
    [MyThumbnailGridView.collectionView invalidate];
// Do view manipulation here.
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

【讨论】:

那是斯威夫特。我正在使用 Obj-C 那也没用。【参考方案2】:

问题在于,当应用旋转时,集合视图本身并没有改变大小。你已经给集合视图一个固定的frame,然后就走开了。所以它永远不会改变。所以永远不要再摆出自己的样子。

您应该将 MyThumbnailGridView 及其集合视图子视图 autolayout 约束 赋予它们的父视图,以便它们在应用旋转时正确更改大小。

【讨论】:

以上是关于UICollectionView 不会在屏幕旋转时更新其布局的主要内容,如果未能解决你的问题,请参考以下文章

屏幕旋转后如何在 UICollectionView 中跟踪单元格的移动

设备旋转时如何自动调整 UICollectionView 的大小?

UICollectionView invalidateLayout 不会在屏幕方向更改时触发 sizeForItem

旋转后在 UICollectionView 中保留第一个可见项目

旋转相机时 DirectX 基元不会在屏幕上移动

应用程序不会填满设备屏幕,启动屏幕也不会自动旋转