6

When testing my app on an iPad using multitasking and I change the app size on the app, the collection view cells need to be resized or else they don't fit in the view window.

I have took some measures such as

  • detecting device to change the size of the cells
  • measure view size to make sure cells fit within the window
  • Add an observer if user changes device orientation

This is all great but however when actually changing the window size when using multitasking, or going back to the full screen app, the cell sizes don't change and look out of place. This is until forced by switching orientation or switching view controllers so viewWillLoad or viewDidLoad gets executed again.

So how can I set a notification if the view.frame size changes ?

nhgrif
  • 61,578
  • 25
  • 134
  • 173
A.Roe
  • 973
  • 3
  • 15
  • 34
  • 1
    It is better if you can set your constraint correctly in storyboard, then there will be nothing much problem. And If you want to know about orientation change, check this .. http://stackoverflow.com/a/25667424/4874185 – Lee Mar 30 '16 at 01:13
  • I am throughout my app, however when working with collection views I have to give the cell a height and width, which of course is tricky as using the same sizes for both iPhone and iPad may not be suitable. So I actually divide the view size to work out suitable sizes, for e.g. on iPhone I fit 3 cells per row, then on iPad I fit 6 (cell.width = self.view.width / 6) - because 3 would look ridiculously large. But when using multitasking the app tries to fit 6 cells when the window is the width of the iPhone and goes off screen. – A.Roe Mar 30 '16 at 01:22
  • The "you should use autolayout" line doesn't stop at table & collection views. But with that said, there is a `updateConstraints` method on `UIView` that gets called, well, when constraints need to update... – nhgrif Mar 30 '16 at 01:33

3 Answers3

13

I think the right function to override is viewWillTransition(to:, with:). It is called whenever the container size is about to change.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    self.collectionView?.collectionViewLayout.invalidateLayout()
}
Jadamec
  • 913
  • 11
  • 13
5

I think you are over complicating the issue, just use the following so when the device is rotated or resized the collection view also changes accordingly.

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    guard let collectionLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
        return
    }

    if UIApplication.shared.statusBarOrientation == UIInterfaceOrientation.landscapeLeft ||
        UIApplication.shared.statusBarOrientation == UIInterfaceOrientation.landscapeRight {
        //here you can do the logic for the cell size if phone is in landscape
    } else {
        //logic if not landscape
    }

    collectionLayout.invalidateLayout()
}
Eduardo Irias
  • 1,043
  • 11
  • 12
RileyDev
  • 2,950
  • 3
  • 26
  • 61
  • Thanks, that works perfectly ! I guess it wasn't a matter of having a notification when the user sizes. I can now clean up some of my code. – A.Roe Mar 30 '16 at 15:48
  • More general, in the override `func viewWillLayoutSubviews() {` the view must be recreated/processed by change of view size in multitasking. In my TableView I had to recreate it, and it worked fine. Amazingly recreated/processed is not necessary by just flipping landscape / portrait mode, but needed for multitasking view size change. – Jan Bergström Jun 07 '20 at 18:12
1

I tried RileyDev answer but the app entered in an infinite loop.

There is no delegate that is executed just when the App's window bounds change, so I've made my own version of the viewWillTransition(to size and traitCollectionDidChange.

With the code below you can detect the window bounds resizing change even if the traits don't change, and resize your collection view cells accordingly invalidating the collection view layout.

var previousWindowBounds: CGRect?

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    if let currentBounds = view.window?.bounds,
        let previousWindowBounds = previousWindowBounds, currentBounds != previousWindowBounds {
        collectionView?.collectionViewLayout.invalidateLayout()
    }

    previousWindowBounds = view.window?.bounds
}
rockdaswift
  • 9,613
  • 5
  • 40
  • 46