Re: Dynamic-width Collection View
Re: Dynamic-width Collection View
- Subject: Re: Dynamic-width Collection View
- From: Doug Hill <email@hidden>
- Date: Wed, 10 Aug 2016 13:29:50 -0700
> On Aug 10, 2016, at 11:10 AM, Doug Hill <email@hidden> wrote:
>
> I'm currently trying to implement something that seems basic but has been driving me nuts: making a Collection View with cells that are dynamic-width and height at runtime.
>
> I was able to accomplish this with Table Views by using the dynamic height constant. Following Apple documentation, I set the width of the table view cell in IB to be an arbitrary size, for example using the default 600 pixels. I then use autolayout to make the size/position of the table view subviews adjust to the size of the cell. At runtime, the table view sets the width of the cell, and autolayout can change the height based on the content (e.g. multi-line labels.)
>
> Now I want to do this using a Collection View. Reading Apple's documentation and watching the relevant WWDC video, it looks like this will be just as easy, right? As is my experience working with Collections, nothing ever comes easy.
>
> OK, so I do basically the same thing as I was doing with tables.
>
> • Create a Collection View Controller in a Storyboard.
> • Create a collection view cell in the collection view inside the Storyboard.
> • Make the cell the width of the collection view.
> • Add some labels that fit the width of the cell using autolayout and allow for multiple lines (e.g. dynamic height)
> • Use the default flow layout in IB and set the item size in the flow layout to be something less than the size of the collection view.
> • Make sure section insets are 0.
> • At runtime during viewDidLoad for the collection view controller, set the item size and estimated item size in the flow layout to be something related to the size of collection
>
> I run this and behold…it crashes. And there are lots of warnings:
>
> "The behavior of the UICollectionViewFlowLayout is not defined because: the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values."
>
> This is kind of odd since I go through a lot of trouble to make sure the cell item size is not too big. Here is what I see for the item size: Yet the app still crashes due to a cell that is too wide for the collection.
>
> So, somewhere else the item size is getting set behind my back to something other than what I set in itemSize, estimatedItemSize, cell bounds, etc.
>
> Before I go any further, I wanted to see if there's an official way to accomplish my goals without doing way more work, that is having to subclass the flow layout class. Should the default flow layout class even be able to do this? I see a lot of different ideas on the interwebs that involve doing things with the flow layout but I'm hesitant to go down that path. Shouldn't this very basic use case be doable without having to get into the complexity of the layout class? Honestly, the documentation for this is terrible. There's a lot of hand-waving and assumptions that don't quite spell out most of the details of this use case.
>
> Thanks.
>
> Doug Hill
Digging into this a little deeper, I find this tidbit in Apple documentation
=============
UICollectionViewFlowLayout: estimatedItemSize
The default value of this property is CGSizeZero. Setting it to any other value causes the collection view to query each cell for its actual size using the cell’s preferredLayoutAttributesFittingAttributes: method
=============
OK, this makes sense why my cells all ended up with the wrong size. The cell class needs to override this method to set the cell's size instead of all the other ways I used above.
Remember, my objective is to make the cell width be the same width as the collection view itself. Huh, collection cells don't have a reference to the collection view it's contained in. Given that I don't know how wide the collection view is, I'll pick an arbitrarily small width so at least the app won't crash. Let's say 300 pixels. I call the cell's super implementation of preferredLayoutAttributesFittingAttributes and then change the frame property of the layout attributes it returns.
Progress! The app no longer crashes right away and the collection cells now have my adjusted width. I do see a couple of problems though:
1) The height of the cell is wrong
It seems to use the default height of the cell as it is layed out in the Storyboard, not the new height of the cell based on my autolayout constraints. This is pretty much the entire reason I'm using the estimatedItemSize property in the first place; it's supposed to figure this out for itself. Ugh.
As a workaround, I can calculate what the height should be based on the origin and height of the multi-line label, and change the layout attributes' frame property to use this.
2) The app still crashes
When scrolling, it will show some number of cells correctly, then I'll see one that has an incorrect width and the app crashes. The crash happens inside the call to the cell's super implementation of preferredLayoutAttributesFittingAttributes, and happens whether I update the height as in #1 above.
OK, so now there is some unsafely when updating the layout attributes returned by calling super's preferredLayoutAttributesFittingAttributes. Digging around in the Apple docs I don't see any mention of anything about how this might be unsafe.
Again, looking for any ideas, pointers, etc. about any of this, including whether I'm going about this the wrong way.
Doug Hill
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden