Timing of CollectionView layouts

I have three CollectionView's. One main collection (Board) view is the game board, which is on auto-layout to be the biggest square possible in the available View space regardless of orientation or device. The second CollectionView (Left) is set up along the left hand edge of the Board and is set to be 30 pixels wide and the same height as the Board. The third CollectionView (Bottom) is set up along the bottom of the Board and is set to be 30 pixels tall and the same width as the Board. I use Layouts to get the content size and cell size within each and cell is always a square. The Left and Bottom CollectionViews sync with the scrolling of the Board CollectionView. This all worked perfectly when I first created it maybe ten years ago.

However, I am currently updating all my apps in Swift (as well as other things). And now, the Left and Bottom CollectionView's are no longer in Sync with the Board. However, it isn't because they don't move correctly (they do). It's because the cell size in the Left and Bottom are not the same size as the Board. I think it has to do with the timing of the Layouts. It configures the size of the cells (in the Left and Bottom) before it resizes the height/width to match the size of the Board.

I've tested this on various devices and it works perfectly fine on the iPad mini, but none of the others. Probably not coincidentally, in the Storyboard setup, I use the iPad mini as the device (to ensure that what I'm doing fits on the smallest screen available). So, the cells are sized as if it were running on an iPad mini even when it's not. The Left and Bottom views themselves are updated to the same height/width of the Board, but the cell sizes are not subsequently updated. Thus, no more syncing.

I tried to reload the data in the ViewWillAppear (first Board, then Left and Bottom), but that does resolve this issue. I had thought that the layout should be handled after any size shifts to the view, but I guess not.

Any thoughts on how to resolve this?

Thanks.

Answered by michaeljmac in 780353022

So, in the end, what was happening was that within the FlowLayout class, the layoutAttributesForItem was using an array of Rects to determine the size of each section and instead of changing to the new sizes, it was simply appending the new sizes to the end of the array, so the UI was always using the same set of rect within the array, regardless of what was happening to the view. The solution was to remove all the items from the array and reset the array with the new size rects each time the view changed size. It now works perfectly well. Thanks for the help on this, the notes above led me to this resulting solution.

It would be much clearer if:

  • you post a screenshot
  • post the code as well as the constraints you defined. As you guess, if it works OK for a single size class, that's most likely a constraint issue.
  • Have errors in the storyboard about the constraints ?

A screenshot of what - the final product or the Storyboard? There really isn't much code to this, but this "cellSize = Int(height * 2 / gridSize)" is in the prepare: function for the Layout class used. "height" = the height of the Left and "gridSize" is a Setting that doesn't change during the game (only in between games). There are no errors in the storyboard about constraints.

As I mentioned, I have tracked it down to a timing issue between when the prepare: function is run to calculate the "cellSize" and when the height of the CollectionView is actually modified to match the Board.

I'm simply trying to figure out how to get all the sizes in place, then have the Layouts determined.

Thanks.

It is whatever information will help analyse your problem. Not your words of what the problem is, but the elements that may help find the root cause.

For instance, the storyboard layout (a screenshot of the view will help) and the constraints you've defined…

I've attached a screenshot of the view with the collection views and the constraints. However, I don't think that's the issue at all. Since, the views are resizing perfectly. It's the layout that is not readjusting when the views change. I have put breaks in the code where the cell size is set and it does not hit that break after the views are adjusted. It hits it before only. That's why I think it must be a timing issue. But if you see anything here that perhaps leads to this issue, I would be happy to try anything.

This is how I have been able to trace the order of occurrence through multiple breaks in the code:

  1. Board, Left, Bottom are all inserted into the view and cell sizes are set at the "default" size (aka the one that is in the Storyboard).
  2. Board is adjusted to its final size based on the auto layout constraints (aka the biggest square that will fit into the space allotted to it in the setup).
  3. The cell sizes are set again for all three (Board, Left, and Bottom).
  4. Left is resized to match the height of Board.
  5. Bottom is resized to match the width of Board.

The view setup is completed. However, now that Left and Bottom are different sizes than when the cell sizes were set for those, the cells for the views don't sync as they are adjusted by the user as they should.

Hope that helps.

Accepted Answer

So, in the end, what was happening was that within the FlowLayout class, the layoutAttributesForItem was using an array of Rects to determine the size of each section and instead of changing to the new sizes, it was simply appending the new sizes to the end of the array, so the UI was always using the same set of rect within the array, regardless of what was happening to the view. The solution was to remove all the items from the array and reset the array with the new size rects each time the view changed size. It now works perfectly well. Thanks for the help on this, the notes above led me to this resulting solution.

Timing of CollectionView layouts
 
 
Q