Large UICollectionViewCell's disappearing with custom layout - iphone

I subclassed UICollectionViewLayout. So far, so good.
However, I have some cells that are wider than the screen, and sometimes these disappear while scrolling. When you scroll some more, they magically reappear where they should be. I can show you my code, however I think there's nothing wrong with it since it works in 90% of the cases.. However, really large cells (more than two times the screen size) disappear sometimes.
NSMutableArray* attributes = [NSMutableArray array];
for (int section=0; section < [[self collectionView] numberOfSections]; section++) {
[attributes addObject:[self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]]];
for (int row=0; row < [[self collectionView] numberOfItemsInSection:section]; row++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:row inSection:section];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
}
return attributes;
I've also these posts: UICollectionView's cell disappearing and Large cells in a UICollectionView getting removed while the cell is still displayed
However, a solution isn't mentioned. Can anybody help me with this? Could it be the problem is on Apple's side? And if it is, is there anything I can do to solve it myself?

Sorry to tell you: I'm pretty sure this a real bug in UICollectionView; I've run into this exact same thing a few weeks ago. I've made a small program to demonstrate the bug and filed a RADAR with Apple, but haven't heard back on whether or if they plan on fixing it. The best workaround I can think of (Warning: I haven't yet implemented this workaround) is to notice that the layout attributes are very far off the edges of the screen, intentionally change the bounds of the cell attributes so it only slightly goes off screen, and possibly store that offset (the amount that you trimmed off of what the real bounds should be) as an additional custom field in the layoutAttributes, so your cell knows to draw it's content correctly. Which feels like a gross hack, but it ought to work.

Are you sure you return the right attribute object for this cell when method -(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect is called and when the rect is just a part of your cell ?

Related

UIView Content Clipping Not Working/UIView Resize Not Working

I ran into an issue where clipping of subviews is not working consistently (or potentially, the UIView resize isn't working). Here's the scenario:
I have a UIView (section above the line). The actual size is larger to accommodate search bar. I basically resize it on viewDidLoad.
When clicking on the text field, UIView expands and show a search bar
After search, I collapse the UIView, but found that the UIView is not collapsed in certain case (see first image). If I were to not hide the search bar, it will remain also.
Is there any reason why this issue occurs? I'm still trying to debug and see if there is anything that could have caused this issue (as something may reset to original size). It definitely does seem like everything is resized correctly since even the result table is moved correctly also. Something else must have triggered it after the expected resize. Any pointer is appreciated. I've only done iOS development for 5 days so I'm still not aware of a lot of things.
- (void)showAddressField
{
CGRect headerFrame = self.searchHeaderView.frame;
headerFrame.size.height = headerHeight + adjustmentSize;
self.searchHeaderView.frame = headerFrame;
CGRect tableFrame = resultTableView.frame;
tableFrame.size.height = tableHeight - adjustmentSize;
tableFrame.origin.y = headerFrame.size.height + statusBarHeight;
resultTableView.frame = tableFrame;
[self renderHeaderBorder:headerFrame.size.height - 1];
}
- (void)hideAddressField
{
CGRect headerFrame = self.searchHeaderView.frame;
headerFrame.size.height = headerHeight;
self.searchHeaderView.frame = headerFrame;
CGRect tableFrame = resultTableView.frame;
tableFrame.size.height = tableHeight;
tableFrame.origin.y = headerHeight + statusBarHeight;
resultTableView.frame = tableFrame;
[self renderHeaderBorder:headerHeight - 1];
}
EDITED
SearchHeaderView is just a UIView that is a subview of the main view. It's not a table header. I found that if I put a search bar in the table header, it behaves very unpredictably so I have a UIView containing the search portion and have a UITableView right below it.
Sorry, since I only have just over a week to get a rather massive app out from scratch, I didn't have time to wait. I already changed my approach a little bit, but I will still award the points even after the bounty has expired. I'm trying to understand everything to do with layout since that's pretty much the only thing that I can't quite figure out with iOS app development.
If the search bar is in the table view header, try reassigning the header view to the table view:
[tableView setTableHeaderView:self.searchHeaderView];
If it is a section header, be sure to update the value for the delegate's
– tableView:heightForHeaderInSection:
– tableView:viewForHeaderInSection:
Otherwise, please post more code on how the searchHeaderView is initialized and added to the table.
Hope this helps!
Firstly, frames are already relative to the enclosing window. You should not be taking into account the height of the status bar (assuming that refers to the 20px area at the top of the screen).
I have found in the past that you may need to implement "layoutSubviews" in your view controller and compute the frames of the views there. It depends on your resizing mask / if you auto-layout enabled.
As the others have stated, more code would be helpful... or at least the relevant portions of the nib/xib.

Pushing a view controller after scrolling is complete

When a user adds an item to my list, I want to scroll to the new row, highlight it, and select it (which will push a new controller). The key part is waiting for the scroll animation to complete before pushing the new controller.
In this answer, I learned how to use the animation delegate to wait until the scroll is complete.
However, if the insertion row is already on scree, the table view will not scroll and the method will not fire.
How can I wait to push the new controller until the end of the scroll, and deal with the case where no scroll will be initiated - and how might I tell the difference between each case?
The easiest way to check whether a given row is visible in your table view is something like this:
if (!CGRectContainsRect([self.tableView bounds], [self.tableView rectForRowAtIndexPath:indexPath])
{
// the row is partially outside the table view’s boundaries and needs to be scrolled for full visibility
}
else
{
// the row is within the boundaries and does not need to be scrolled
}
Try creating a method to see if scrolling is needed. If no scrolling is needed, call the push right away, otherwise wait for the delegate call and push.
- (BOOL)isSrollingingNeededForIndexPath:(NSIndexPath *)indexPath {
NSArray *visibleIndices = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *visibleIndexPath in visibleIndices)
if ([indexPath compare:visibleIndexPath] == NSOrderedSame)
return NO;
return YES;
}
Edit: Good point. Since indexPathsForVisibleRows is used for data rendering.
You could do essentially the same thing with indexPathsForRowsInRect where you use the content.offset.y and the tableview.frame.size.height to determine your "visible rect".
Then to account for partially visible rows at the top and bottom you could add rowHeight-1 to the top of the rect and subtract rowHeight - 1 from the bottom of the rect. Code shouldn't be too gnarly if you have static height rows. If you have varying height rows it would still work, but it would be a bit more involved.
All said though, it seems like a lot of code for something which you'd think would have a simple answer.

Last Section Header View not painted after insertRowForIndexpath and deleteRowForIndexpath

I have a setup with sections in a UITableView which all have a custom section header view. Only one section at a time can have visible rows.
To create an effect that displays other cell rows I basically use the following function:
[self.tableView beginUpdates];
if ( sectionHeaderInsert >= 0 && sectionHeaderInsert <= numberOfSectionsInTableView ) {
[ticketReastepsScreenView.tableView insertRowsAtIndexPaths:indexPathsInsert withRowAnimation:UITableViewRowAnimationFade];
}
[self updateTmpSelectedNumberToCurrent];
if ( sectionHeaderRemove >= 0 && sectionHeaderRemove <= numberOfSectionsInTableView ) {
[ticketReastepsScreenView.tableView deleteRowsAtIndexPaths:indexPathsRemove withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
Now what happens is that in the end the new section "opens" and the old one "closes" propperly, but: if I have more sections that fit on the screen the last section that is (partly) visible will not repaint propperly - it is completely covered in white.
All sections are asked gor new heights and I think it even asks for new views (which I hae in an array). The views are then asked to [view setNeedsDisplay];
When I scroll a bit so that the last section header disappears and then scroll it back in, it comes to life again and is visible until I change the currently open section again.
UPD: This funny behavior only appears when I do the insertRow and deleteRow together. I can also simply close one section (deleteRow) and then in a section touch-action open the new one (insertRow) and the behavior is different.
I also tried having an endUpdates and beginUpdates in between the two actions - no positive result.
UPD2: When transitioning to the final position (positions are good) I can see the last section header being painted correctly, but then disappear (no animation, simple plain white over it)
Whatever the REAL problem was - I rewrote heavy parts of the TableView and I think what I've learned is:
If you need a UITableViewCell, use a UITableViewCell. If you need a UIView for the section headers, use a UIView for the section headers.
I've mixed the section headers with the TableViewCells just to re-use some code I had in there. Since categories can only extend one specific class I had to use delegation/provider methods/objects to re-use certain code. It may need more subclassing but is actually much safer.
In addition auto-scrolling to a position now works significantly better and the drawing artifacts are gone.

Objective C: Change table cell configuration based on previous/next cell

Is there any way to change something about a table cell on the iPhone based on the previous or next table cell before that cell is displayed? This might be confusing, so here's an example:
Let's say I have a table like this (I'm just going to fill it with random values, so don't worry about the text contained in the cells):
*Cat
*Rabbit
*Dog
*Mouse
and there was a imageView.image attached to some cells (different images for different animals and you don't know which ones might have images) and at some point (programmatically) new animals are entered into the list sandwiching the animals that are already entered like so:
*[animal]
*Cat
*[animal]
*Rabbit
*[animal]
*Dog
*[animal]
*Mouse
*[animal]
How would I go about moving the images associated with the previously listed animals?
Hopefully you get a kick out of how ridiculous this question sounds, but I swear it is a serious question that is driving me insane and I didn't know how else to describe it.
Felixs' answer probably works, but it sounds like you are thinking of it from view-manipulation angle, and not a model-manipulation angle. It sounds like you really have two parallel models: the list of animals and the set of images. Why not just reloadData when either thing changes and rebuild the cells appropriately from inside your controller?
Reaching into existing cells based on their index feels fragile to me.
I hope I've got the right end of the stick here, but: In the cellForRowAtIndexPath: method, you could get a pointer to the previous cell (and so any associated images, text, etc.):
NSIndexPath *indexPathForPreviousCell=[NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
UITableViewCell *previousCell=[tableView cellForRowAtIndexPath:indexPathForPreviousCell];
I hope this is what you needed...

Design cell make UITableView slow

Here is my problematique: I design my cell in my UItableView, so I added a title, a little description and an image.
All thoses element are store in my database, so in my UIViewController I calculate every position to have a nice cell, if there is no image in a cell I change the position of the title and the little description.
To check if the image is present or not I do something like that:
if ([fiche linkImg]!=#"") { //draw position of element }
or
if ([fiche.linkImg length] > 0 ) { //draw position of element }
My problem is when I begin to slide in my tableview its very slow and often very often crash, and the error are sometimes:
[CALayerArray listImg]
or
[NSCFArray listImg]:
Any idea?
Your description is a tiny bit confusing to see what is the problem.
I would suggest having a look at how to accomplish adding custom stuff to cell.
Have a read of apple's doc on UITableView especially a closer look at Table-View cells, if you scroll down in that section you will find examples of exactly the type of cells you are trying to create (text with pictures).
Try adding like this
if([fiche linkImg]!=nil)
I tried and succeeded