UICollectionViewCell with variable image size and AutoLayout - ios

I'm trying to display an UIImageView in a UICollectionViewCell that is loaded after the cell is displayed initially.
To not display a white are I use a fallback image. This has a different size than the image to displayed later.
The sizeForItemAtIndexPath thus is called at a time when the bigger fallback picture is displayed and returns a size that is too big for the eventually loaded image.
I've implemented a delegate to call a method after the image has finished loading. The delegate method then calls reloadItemsAtIndexPaths on the UICollectionView with the indexPath of the cell that finished loading. This happens only if the calculated height of the cell now differs from the value calculated before. The image is also stored in cache after the initial load. Together this ensures that the reloadItemsAtIndexPaths method is only called once.
Although this works in general I'm not sure if it's the best practice. It also doesn't have the best performance and with small network speeds my layout doesn't look very good.
Has anyone ever encountered the same problem or was trying to dynamically resize single cells in the UICollectionView?

I had a similar problem with an image viewing app. I used invalidateLayout on the collectionViewLayout property of the collection view. It doesn't reload the cell, but calls sizeForItemAtIndexPath for the visible cells.

Related

Dynamic cell height issue with UITableViewCell autolayout jerk while scrolling

I am trying to do something like loading up different type of cells with custom height in a uitableview. The tableview cells are subclassed and consists of labels with the respective constraints. Each cell is having a dynamic height.
Now even before my table reloads the data, I am calculating the height that is required for the resizing of the cells and caching it in my model class so that I dont have to calculate the height when the data is rendered on the device.
To calculate height i did use the tutorial from Ray Wenderlich and I am having the right set of heights applies to the objects.
Now the problem comes. Whenever I am dequeueing the cells there is a
kind of a small jerk that gives me an indication that my cell is
dequeued while scrolling.
How can i make these movement smooth so that there is no jerk while scrolling the view ?
The height is getting assigned in and does get the value as per the current type of data getting loaded.
estimatedRowForIndexPath
Also I am calling layoutIfNeeded from my cellForAtindexPath
Suggestions are most welcome.
It's very hard to say without seeing your code in cellForRowAtIndexPath, and without seeing your cells and their respective code. Here are some general questions I would investigate:
What is the content of the cells and how complex is the view hierarchy in the cell?
Even though you are supplying the correct estimated height, an autolayout pass still needs to happen, and a complex view hierarchy will take time to resolve
Does the cell contain images?
Images that need to be decompressed from a file (UIImage imageNamed:) can be intensive and cause scrolling issues, check images are not bigger than they need to be. If needed, bump this work onto a background thread.
Are you calling a complex method to configure the cell for display in cellForRowAtIndexPath?
Look at the work actually being done in cellForRowAtIndexPath, is there a complex method being triggered in you cell subclass or view model?
Are you adding and removing views to the cell view hierarchy in cellForRowAtIndexPath?
If views are being added, removed, created, inflated from a xib, constrained etc during the cell config, this could slow things down. Try to do only what is strictly needed. Check if there is any code being run internally in the cell subclass during cellForRowAtIndexPath that could be moved to cells initWith... or awakeFromNib methods (ie code that could just run once when the cell is created, rather than every time the cell is displayed)
Also run the Instruments time profiler, see if that offers any more clues

UIViewController calls sizeForItemAtIndexPath for all cells on load

I have a UICollectionView with UICollectionViewFlowLayout. While testing with large data (5,000+ cells) I noticed a lag when loading. I found out that at loading the sizeForItemAtIndexPath is called for EVERY cell. Since I am doing a messaging like application and each cell is of different height, this causes height estimation to occur. I am not scrolling to the bottom or anything, just loading the view.
I have made a small app demonstrating what I am saying (look at the console to see that it is calling sizeForItemAtIndexPath for all cells) https://github.com/ftheo/CollectionViewLoadingBug
Any help would be appreciated. Thanks
Maybe there is no way to prevent calling sizeForItemAtIndexPath method...
That is normal design for calculating scroll content view size.
The collection view needs to know what size it's contents have, hence it calls -sizeForItemAtIndexPath:. There is no way around this.
Consider using a UITableView instead. It offers a method
-tableView:estimatedHeightForRowAtIndexPath: where you give it a rough guess for offscreen cells.

Re-Enabling dequeuing on a UICollectionView within a UIScrollView

I'm trying to set up a particularly large UICollectionView, and I'm embedding it within a UIScrollView (as per this answer to another question on SO) in order to support scrolling in both directions. I've got it up and running, everything is working perfectly, except that performance takes a HUGE hit as the size of the CollectionView grows.
After some hunting around, I was able to figure out the problem: because that SO answer calls for the CollectionView to be resized so that all the cells are visible at once, "dequeuing" isn't a thing anymore. The CollectionView within the ScrollView has dimensions of 2000x2000 (or whatever), so even though the ScrollView is just the size of the screen and only shows 20 cells or so at a time, the CollectionView thinks all cells are visible and needed right now. Thus, every cell in the CollectionView is generated at once, meaning the page takes a ludicrously long time to appear.
Is there a way to communicate to the CollectionView which cells are currently visible through the ScrollView, so it doesn't generate unnecessary cells and dequeues them as normal? Or if not, is there a way to make a CollectionView that scrolls diagonally, but that doesn't have this problem?

Call to reloadRowsAtIndexPaths breaks the setImageWithURLRequest

I have the problem with image loaded to the header cell, the problem was that requested image was not loaded (displayed as it turns out) and only the image loaded on view load was used.
I have narrowed the problem - I'm calling sizeToFit to resize label and then if the size is greater then minimum cell size I'm notifying delegate that I need new size of the cell. The delegate function calls reloadRowsAtIndexPaths:withRowAnimation: on the cell that was requesting resize. The tableView:heightForRowAtIndexPath: is called which is using new size.
I need this behaviour though as the cell needs to grow/shrink to accommodate the amount of text.
Has anyone faced similar issue, and most importantly has anyone got any workaround?
This is a sample project that shows this issue, if you go to the CSTitleCell and method resize to comment-out the delegate call you will see that it starts to work (but not resizing of the cell). Change of the content is done through swipe left/right.

How to change cell's size dynamically in a custom UICollectionView without implementing collectionView:layout:sizeForItemAtIndexPath:

I have created my own layout by subclassing the UICollectionViewLayout class, and not the UICollectionViewFlowLayout one. Hence it seems that I cannot implement the method collectionView:layout:sizeForItemAtIndexPath:.
Unfortunately, I may want to change my cell's sizes dynamically. For instance, I have a set a little circular cells around a big cell. When the user exchange a small cell with the big one, I want the little cell to take the location and the size of the big cell, while the big cell would get as small as the little cell and it would take its location. I already managed to do the location exchange (with the moveItemAtIndexPath:toIndexPath: method) but the cell won't change their size.
I understand that the layout is the only responsible for updating item's size, but I can assure that I have tried anything and the cells still don't resize.
Does anyone have an idea of what I could do? I would be very grateful!

Resources