Hide a UITableView by setting row height to 0? - iphone

I just inherited code which hides/shows rows a UITableView by using the delegate heightForRowAtIndexPath method and returning height 0 for "hidden rows".
The code works, but it has me concerned there might be fraught with unforeseen complications. Can someone either ease my concerns or give me good reasons why this could cause problems (I couldn't find any issues with initial testing).
The table is fairly small <10 rows total and would require custom row heights even without this hidden row solution.

I do the same thing in the code I just worked on. I am not happy with different behaviour for different table view settings.
The alternative in my case is more complex (a model that adapts to what is visible or not).
For now, I put a //HACK comment on it and document a few peculiarities.
This is what I have found (iOS 5.0 tested):
Set tableView.rowHeight = 1; Zero will give a cell with zero height (as returned by tableView:tableView heightForRowAtIndexPath:) some default height.
You must have a cell separator. If none is selected, then a default height is assigned to zero height rows. The height of 1 is included with the separator.
If your code works in a different way, it would be interesting to know how it is set up.

It would be cleaner to add and remove the rows between two beginUpdates and endUpdates calls, but I don't see why this 0-height method should not work.
If there are no UI-artifacts, that is (e.g. the Delete button showing up overflowing to the next cell).

I use this method of setting hidden cell heights to 0. It works well and also means I can animate the inclusion of new cells by expanding the cell height (such as adding a DatePicker Cell like the calendar app does).
A few things I have had to watch out for in iOS 7.1 are that very squashed text does still appear even when a cell height is = 0 so I've needed to remove cell text in that case. Also, I have change the size of the cell's separatorInset as that was appearing as well.

Related

How to add space between rows in NSTableView

I'm trying to add spaces in between rows in an NSTableView, like how it looks here.
Currently, however, my rows look like this, with 0 spacing between them.
Is it possible to add these spaces? I found this post on how to do it, but that's for UITableView, and I don't think you can add sections with NSTableView. Another thing I tried was using intercellSpacing on the table view, like so:
tableView.intercellSpacing = NSSize(width: 0, height: 80)
However, that just increases the height of each row rather than increase the space between them.
Lastly, I looked into drawSeparator, which seems promising but has limited documentation. Would extending NSTableRowView and overriding the drawSeparator method work, basically by drawing in a blank space as the separator? If so, how would I go about making my table view use my custom row view class?
If none of these options work, I'd also be open to faking the effect, maybe by having the actual content of a row be smaller than the row itself and using the remaining space as the padding between rows. However, I'm not sure if this would work, given that right now I'm using NSShadow, which highlights the boundary of each row.
Found a way to work around this issue. Before, each row consisted of two columns, one for the text fields and one for the buttons. However, I've changed it by putting all the text fields and buttons into a single column, that way there's only one cell per row. I then can apply the NSShadow and other styles to the NSTableCellView rather than the NSTableRowView. This means that I can now use intercellSpacing to create vertical spacing between cells:
tableView.intercellSpacing = NSSize(width: 0, height: 80)
The rows are still touching, but I've disabled the borders/highlighting on them so you can't actually see them. The cells, on the other hand, are visible, and you can adjust the spacing/styles on them as necessary.

Autolayout Error with UITableView

I have a TableView and I specify the height for each cell using the delegate method tableView:heightForRowAtIndexPath:.
When I rotate the view I get this error that I don't quite understand.
It can't satisfy the constraint below and breaks it to continue.
"<_UIScrollViewAutomaticContentSizeConstraint:0x8e8d040 UITableView:0x9423400.contentHeight{id: 213} == -1568.000000>"
Does anyone know what is happening and why I'm breaking this constraint?
UPDATE: This issue is no longer relevant in iOS 8, which adds support for self-sizing cells. It is still relevant for iOS 7 however.
Original answer (iOS 7):
Greg's answer definitely worked for me - I needed to debug my tableView:estimatedHeightForRowAtIndexPath: method. I did some debugging and some quick experiments and here are some things I learned:
Don't use UITableViewAutomaticDimension in the estimated row methods. This constant is for the header and footer methods. I guess I wasn't paying enough attention when I read the documentation :) UPDATE: UITableViewAutomaticDimension can now be used for row heights in iOS 8, part of the self-sizing cells functionality.
Estimating row height of 1.0 results in an exception: "NSInternalInconsistencyException', reason: 'table view row height must not be negative...'" Estimating less than 1.0 has strange results as well.
Estimating between 2.0 and the actual works just fine without any exceptions (although 2.0 is probably a bad choice for optimization reasons - you want to be as close to actual as possible).
The constraint exception only occurs when the estimated row height is greater than the actual row height. The closer you are to the actual, the less likely the exception will occur. How far off your estimate can be before getting the exception seems to be related to several different factors: actual row height, the position of the row, etc.
tl;dr: Look for actual height values drastically different than what you estimated. Or actual values that are negative or 0.
I just spent a few minutes debugging this constraint exception. I have a UITableView with cells, section headers, and section footers. Each of these had the iOS 7 estimatedHeightFor messages defined, returning a static const value. I removed cells, headers, and footers, one at a time until I determined the issue was coming from the footer (not important if you don't have footers, please read on).
If I eliminated estimatedHeightForFooterInSection:, the exception disappeared. In my heightForFooterInSection:, there is one path in which the height of the footer would be 0. When I restored the estimatedHeight message and eliminated the code path for an actual height of 0, the exception also went away. I replaced 0 with 22 and decreased this value all the way to 12 before the exception reappeared.
Regardless, I need the height of the footer to be 0 (I return nil from viewForFooterInSection: in that case) and I want to be able to estimate the height (I am supporting Dynamic Text). My solution was to account for the code path that would give me a 0 height in estimatedHeightForFooterInSection:. Once I added that, the exception went away.
Try to debug your
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
implementation. In my case it was returning a negative integer in some rare cases, resulting in the message showing up in my log and messing with the scrolling behavior of my table view.

set the page size with UITableView and paging.enabled=YES (or other way ?)

I'm struggling with this problem, although I'm close to the solution, but I guessing I'm missing something.
Here is the situation :
I have UITableView with 30 cells, and one section header (if it's helpful..).
The table size is exactly the size of 3 rows.
The mission : to let the user scroll 3 rows everytime, exactly 3.
I set the pagingEnabled=YES.
What happens is :
"page 1" - 3 rows - ok (rows 0-2)
swiping to "page 2" - next 3 rows - ok (row 3-5)
swiping to "page 3" - and the paging is not good, either skiping row 6 and showing row 7-9
or the page is stopped in the middle of the cell of 6 (also tried to move the scroll to complete cell visibilty with scolling end event, but it skips some of the rows on some pages)
Any ideas how to fix the situation, every page = 3 rows only ,without skipping or showing half of cell ?
I don't mind if the way will be without pagingEnabled=YES.
I arrived at the conclusion this is basic thing I will use in the future , and I think a lot of others will use the solution that other friends will give here.
Thanks.
Never thought of using this property in a Table View.
Since it is a subclass of UIScrollView, try instead to use the UIScrollViewDelegate methods and calculate where to stop.
A good place to start can be in scrollViewWillEndDragging:withVelocity:targetContentOffset:. and return the offset yourself.
P.S.
from the documentation:
This method is not called when the value of the scroll view’s
pagingEnabled property is YES. Your application can change the value
of the targetContentOffset parameter to adjust where the scrollview
finishes its scrolling animation.

Best (Any) way blend tableview section header onto top of a grouped tableview

I'd like to add section headers to my grouped table view's sections but I'd like them to appear seamless (see image). The default, as we're all well aware of, is rounded top corners on the first row of a grouped table view cell so it ends up looking like crap when you merge them.
Any way to specify when indexPath.row = 0 that the UITableViewCell should use row style "middle" or something like that?
If not then what are my options? I guess I could scratch the section header and use Row 0 as a quasi-header then push my array data +1 to fill the rest of the table? I'd rather not roll my own from scratch...if possible.
Sample Table http://img35.imageshack.us/img35/8181/sampletable.png
Edit:
"Crap" looks like this:
alt text http://img25.imageshack.us/img25/9748/crapsection.png
Don't do what you're doing, it's against HIG
Ok, ok, I'll tell you how to do it:
You're going to want to do your own cell background views. The default grouped one is not what you want.
When a tableview asks you for a cell, set its backgroundView and selectedBackgroundView to something that looks appropriate for its place in the tableview.
Usually, this means a UIImageView with the appropriate image, though you can go wild here with a custom view, but there are gotchas.
So in your case, you would do
if (indexPath.row > sectionRowCount - 1) {
//Not the last row
//Put in the middle background
} else {
//Put in the end background
}
Then you'll want a custom table section header, but that's pretty easy.
In your case, you probably won't have to worry about when there's just one row, so that makes things even easier.
Take a look at the tutorial here:
cocoa with love basically what you need is 3 different images. One for the top row, one for the bottom, and a 3rd for the middle rows.
You could also not use the section header, but instead use a custom cell as the first cell of the section. So when ([indexPath row] == 0), return a custom cell that is the "header" and then return the "regular" cells (offset by one row) for the rest. You'll also have to make adjustments to the numberOfRowsInSection function to return +1.

UITableView: moving a row into an empty section

I have a UITableView with some empty sections. I'd like the user to be able to move a row into them using the standard edit mode controls. The only way I can do it so far is to have a dummy row in my "empty" sections and try to hide it by using tableView:heightForRowAtIndexPath: to give the dummy row a height of zero. This seems to leave it as a 1-pixel row. I can probably hide this by making a special type of cell that's just filled with [UIColor groupTableViewBackgroundColor], but is there a better way?
This is all in the grouped mode of UITableView.
UPDATE: Looks like moving rows into empty sections is possible without any tricks, but the "sensitivity" is bad enough that you DO need tricks in order to make it usable for general users (who won't be patient enough to slowly hover the row around the empty section until things click).
I found that in iOS 4.3, the dummy row needs to have a height of at least 1 pixel in order to give the desired effect of allowing a row to be moved into that section.
I also found that the dummy row is only needed in the first and last section; any sections in between don't have this problem.
And it looks like in iOS 5.0, no dummy rows or special tricks are needed at all.
While managing the edit, you can monitor if the table view is in Edit Mode. Use that flag inside of cellForRowAtIndexPath to decide weather or not to display the 'blank' row. While in 'regular' mode, the row will not display, but when the user taps 'edit' cellForRowAtIndexPath should get called again and this time decide to display the row. The details of how to do that depend on your data source and how you are gluing it to the display. If you aren't getting the call again, you can manually inject rows with insertRowsAtIndexPaths / deleteRowsAtIndexPaths and/or call reloadData to force a refresh.
I found that if you return -1.0 from the heightForRowAtIndexPath method it will remove the 1 pixel line.