2

I'm having a problem adjusting a parent view's layout when orientation changes for it's child view. I have a collection view controller that, when one of the cells are tapped, pushes a child view on top. If an orientation change occurs while the child view is visible and it is dismissed, the parent view's collection view cells haven't adjusted for the new width.

I should note that this works fine if the parent view is visible.

The only thing that has fixed this for me is in the viewDidAppear method of the parent view controller invalidates the collection view layout, but for me it's too late as the user sees the animation of the collection view cells snap into place.

- (void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [self.collectionView.collectionViewLayout invalidateLayout];
    [self.collectionView reloadData];
}

I would have preferred to use viewWillAppear, but that doesn't seem to do anything. It sounds like it can only adjust the cells when the parent view is visible.

Is there a way around this?

Brandon
  • 2,886
  • 3
  • 29
  • 44

3 Answers3

2

Referring to this answer, iOS does not send orientation change events to offscreen view controllers, making them an unreliable way to determine whether the view has been resized.

viewWillAppear: isn't working in your case because iOS doesn't resize the offscreen view controller's view until after it calls the method, so your invalidate and reload are being pulled off the wrong values.

I believe the iOS8+ viewWillTransitionToSize:withTransitionCoordinator: method fires even when offscreen, but I'm not positive. In my experience, the size it provides does not reflect the actual size of the view. What I personally like to hook into is viewWillLayoutSubviews, usually guarded with a width check:

@property (nonatomic) CGFloat lastWidth;

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    if (self.lastWidth != CGRectGetWidth(self.view.bounds)) {
        self.lastWidth = CGRectGetWidth(self.view.bounds);

        // Update your collection view here.
    }
}

This way, whenever your view is going to resize (on display, inside an orientation change animation) you can update the size information.

Community
  • 1
  • 1
Brian Nickel
  • 26,890
  • 5
  • 80
  • 110
  • I'm on iOS 10 and `viewWillTransitionToSize:withTransitionCoordinator:` _is_ called when a view controller is offscreen as you suggest. However, _given_ a view controller is offscreen _when_ a rotation occurs _then_ the view bounds are reporter incorrectly in this call (using `animateAlongsideTransition:completion:` on the `coordinator`). The bounds always seem to be portrait. When the view controller is _on screen_, the bounds are correct. `viewWillLayoutSubviews` does not have this problem. – Benjohn Jul 07 '17 at 07:50
1

try overriding -(void)viewWillLayoutSubviews: method in your parent view controller. In your case,it goes like this

-(void)viewWillLayoutSubviews {

[self.collectionView.collectionViewLayout invalidateLayout];[self.collectionView reloadData];
}
demonplus
  • 5,613
  • 12
  • 49
  • 68
0

You could try invalidating your layout and reloading in the rotation handler methods.

For pre-iOS 8

willRotateToInterfaceOrientation:duration:

And for iOS 8+

viewWillTransitionToSize:withTransitionCoordinator:
stevekohls
  • 2,214
  • 23
  • 29