UICollectionView SupplementaryViews for Empty Sections - iphone

I'm trying to create a collection view that imitates a scatter plot by using a custom layout object.
I'm using the number of sections to reflect the x values, and the number of rows in section to represent the number of y values per x value. I've also got another protocol method that asks for the value of the Ys, but thats not relevant.
Anyway, it is entirely possible that a particular section has 0 data points. However, I'd still like that section to display a supplementary view, but I am finding that this method:
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
is not being called in the empty sections. I guess it makes sense since the indexpath doesn't really exist.
Note: I am using a custom layout, not a flowlayout, so I don't think the header/footer views apply here.
Anyway, does anyone have any insights into how I can add a supplementary view to an empty section?

Related

Double-sectioned expandable tableview

I am currently facing a big issue in my coding, but I can't find any solution.
Just as you can see here, I would like to create an expandable tableview with:
categories split into 2 sections
subcategories
I mean, if you click on "2A", the "2A-1", "2A-2" etc. list is expanded. If you click on "2B", the "2B-1", "2B-2" list is, and so on.
How do you think I could manage it?
I've written a solution of this nature in a few products. The code to accomplish this is a bit extensive, so I will give you a high level overview.
Create each "row" as a section. Obviously, override viewForHeaderInSection and so forth in order to make each section header actually look like a row.
Have your view controller hold an array of which sections are expanded (non expanded are collapsed)
In the - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section check to see if the section is expanded, if it is, then return the number of subitems, otherwise, return 0.
hence, the cellForRowAtIndexPath always returns just the subItems, and the viewForHeaderInSection always returns the parent.
When the user clicks on the header cell, toggle the section expanded flag, and reloadSections:withRowAnimation: to get a nice animated transition
one note, since prior to IOS6, section headers were ALWAYS recreated and NEVER cached, the performance was not great. With IOS6, this issue is solved as it recycles header cells too.
For expandable cells you can use VPPDropDown class, i used it myself, it's good :)

Can a UITableView index jump to a row instead of a section?

I have implemented a UITableView with only one giant section and now I need to implement an index to this UITableView (something like the contacts apps) however my index does not represent sections it represents rows. And as far as I know you can only jump to a section and not to a row with the index in tableview.
I don't want to add sections because then I'll have to add a section for each row, which would be kinda stupid.
So my question is: Is there any way to implement an index to a UITableView such that it when I tap on any part of the index it takes me to the relative row instead of section in the tableview?
I would probably endup writing a hack for this thing which a really wanna avoid and do it the way it should be done (if there is any such way) so any help would be greatly appreciated. Cheers!
Just implement the sections and set their height to 0 in tableView:heightForHeaderInSection:
It's not such a big hack. Just change rows for sections with one row. Move what you have in tableView:numberOfRowsInSection: to numberOfSectionsInTableView:. You have to slightly adapt cellForRowAtIndexPath: to check the section you are in instead of the row and there you are.
Use this method:
- (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated;

Best practices for drawing dynamic UITableView row height

Possibly a duplicate but I couldn't find a specific question on SO, so here it is.
I'm curious about dynamically changing heights for all rows, typically, because you don't know the length of an NSString that's used for a label.
I know you must use this delegate method to change the row heights:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
The problem is this delegate method is called BEFORE the cell is created (i.e. called before cellForRowAtIndexPath).
So, what I've thought of is to create a mock cell in viewWillAppear and a method that adds cell heights to an array that maps to the table view's data source (which in my case is also an array).
viewWillAppear implements this one important method to get the height:
[NSString sizeWithFont: constrainedToSize: lineBreakMode:]
Then in heightForRowAtIndexPath I can return the cell height like so:
//cellHeights is an ivar populated in viewWillAppear
return [[cellHeights objectAtIndex:indexPath.row] floatValue];
I was wondering if there was a better way to dynamically change the row height?
I realize this will degrade performance for a large number of rows (greater than 1000, I believe). But in my case, my rows won't ever come close to that number. So the performance hit is negligible.
Thanks in advance!
Great question! In fact, I did something similar in some of my applications.
I can think of a couple of alternatives, but all of these are along the same theme. You could also just to use sizeWithFont: inside of heightForRowAtIndexPath: and do away with the array. In that case, you might take a performance hit for recalculating the size each time, if that operation is expensive.
You could do "lazy loading" of the cellHeights array inside of heightForRowAtIndexPAth: so it might look something like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cellHeights objectAtIndex:indexPath.row] == nil) {
... calculate height and store it in the array at the correct index...
}
return [[cellHeights objectAtIndex:indexPath.row] floatValue];
}
The advantage I am thinking of here is that you will only calculate the heights for cells that are definitely going to be loaded. If you do the calculation in viewWillAppear, I guess you end up doing it for every cell, regardless of whether it is displayed?
Finally, you could put the size in your data model itself. If it is, for example, an array of strings, you could make a class that has two properties: a string and a "representationSize" property. Then you can recalculate the size of the string each time the value of the string is changed. Then, there would just be one array, not two, that maps onto your data source, filled with a data class containing both the string and display size of the string, and the value would be calculated when the string changes, not at all once when the view appears.
Anyway, I would love to hear some comments about these various approaches.
Matthew's idea of putting the height in the data model sounds interesting. Here's another answer that proposes a very similar solution: How can I do variable height table cells on the iPhone properly?
I have too problem in my UITableView,when I scroll tableview (on 3gs iPhone). I saw a lot of lags. So i open time profiler (very good tool for optimization) and problem was when I call function sizeWithFont. The best solution for resolve this problem is call sizeWithFont in constructor.

heightForRowAtIndexPath for only one section?

This is the problem I'm facing right now:
I've got a lot of UITableViews with two sections each (only one is displayed at any time, on demand). The first section has got 3 cells, which might need to be resized. Because of that, I'm using heightForRowAtIndexPath.
The second section might have up to 3.000 cells, all using the default height of 44 points.
My heightForRowAtIndexPath determines whether it is treating a cell from section 1 or from section 2 and then either measures (section 1) or immediately returns the default value (44 section 2).
By using this method, large table views take a little while to be displayed, since heightForRowAtIndexPath is a performance issue in cases like this (more than about 1.000 cells).
My question is:
Is there any way to resize just the 3 cells presented in the first section? Any way to maybe force heightForRowAtIndexPath to be called just for indexPath.section == 0?
In case it makes any difference, I'm using a grouped table view.
Thanks.
heightForRowAtIndexPath is going to be called if it is implemented in your delegate. If you're only looking to change the values in the first section, then just use a simple if statement. This could look like:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
// Test to see what section you're in
if ([indexPath section] == 0) {
// return the height for the first section
} else {
// return the height for everything other than the first section
}
}
Cheers.
Why not just use 2 table views--one for your top section, and one for the second section?
You could either give each UITableView a different delegate, or if they share the delegate, you could return immediately from heightForRowAtIndexPath for the bottom UITableView.
I'd probably give them each a different delegate, to avoid a lot of switching in the delegate methods to figure out which section you're in.

How can I find out the name, ID, or type of a UITableView Cell?

-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if([tableView.somethingMagicalHereThatAllowsMeKnowWhichCellItIs isEqualToString:#"CellType"]){
return 50;
}
return 25;}
I have tableView with multiple cells of different types, and I want to style them accordingly, but the problem is that I don't know which type it is when it comes in. I can't use indexPath because the cells are in no specific order. Is there a way to show the id?
What I usually do is remove the “what goes in which table view cell” from -tableView:cellForRowAtIndexPath: and put it in a separate method. How I name this depends on what I’m trying to achieve. One typical scenario is that each cell represents an object. In that case, I define a method like this:
- (SomeObject*)objectForRowAtIndexPath:(NSIndexPath*)indexPath;
Then, in both -tableView:cellForRowAtIndexPath: and -tableView:heightForRowAtIndexPath:, I call that method to find out which object corresponds to that cell, then either create the cell or set its height accordingly.