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.
Related
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.
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
How can I update all the cell sizes of UICollectionView?
I am changing the frame of UICollectionView, and want to change its UICollectionViewCells sizes accordingly
I'm not sure what actually the problem is, but here is steps, that can help you to achieve what you want:
Define your collection view layout delegate (I assume that you use flow layout or its descendant)
Implement - collectionView:layout:sizeForItemAtIndexPath: (see docs) and compute cell size based on collectionView
When you change your collection view's frame call invalidateLayout (see docs). It will force delegate to call sizeForItemAtIndexPath
If you have any questions - feel free to ask. It would be better if you provide some code snippets and explain what kind of difficulties do you have.
I am creating views at run time using heavy data, and adding these views to a UIScrollView.
The problem here is,it takes a lote of time to create the screen, which is not so good user experience.
I want to create initialy only for the part of screen that are visible, and add/create the others views when scrolling the UIScrollView.
Any tips about the best approuch?
Thanks in advance
You can use the UITableView, set cell separator to none and use variable height of row cell. Do as you always do with UITableViewCell i.e. deque cell using identifier.
This is the best approach to deal with the memory issue and for large amount of data.
Also you can do the same for UICollectionViewCell too.
What would the pattern be for sizing a UICollectionViewCell based on some content I've downloaded? I wouldnt know the size when the cell gets created - it would be sometime after my content has downloaded that the cell would callback with its height. What would I call on the collectionview to have it re layout its cells?
I've faced this with tableviews and ended up calculating the height based on the strings and controls in the cell. But in that case essentially everything was a function of data already in my model. Thats not the case here.
Thanks,
Jason
Depending on the number of cells you will displaying (e.g. a small # of cells), simply calling [UICollectionView reloadData] will do the trick once you know the different heights from that network callback.
I think that the the RFQuiltLayout can solve your problem.
Use the function
(CGSize) blockSizeForItemAtIndexPath:(NSIndexPath *)indexPath
Here is the link https://github.com/bryceredd/RFQuiltLayout