TableView height in Swift - swift

My tableview add blank space to the end of the cells.
I don't know why, how do I fix this problem? (For ex I have 50 cells, two of them you can see here because this is last two cells)

Hard to know without seeing your code, but because your cells have varied heights, you should probably start by implementing tableView:heightForRowAtIndexPath:
If you end up wanting more manual control over the table's height, take a look at its contentSize property.

Related

How many UILabels can be added to a View

I want to add about 300 grids to a UIView,It is OK if I use 300 UILabels?
Or,besides UILabel,any better way to deal with it?
Grid means what you can make a UITableView with 300 rows and you can make any number of labels in your UIView
Perhaps start here. Other than that, I don't see a problem with UILabels, with that count, it might get slower though. Imagine how many objects you will be rendering...
If you create a UITableView with reusable cells, only the visible cells will be populated at any one time, so only those UILabels (assuming one or more per cell) will actually exist at any one time. Not a problem.

Show a label over the limits of a UITableViewCell

I'd like to use a UItableView to show a day Calendar. Each row corresponds to one hour. I need to show the hour between 2 cell of my tableview.
Like this :
(source: free.fr)
And this is my UITableViewCell :
(source: free.fr)
In the first screenshot, it works perfectly but if I scroll down then scroll up, my time label is cut like this :
(source: free.fr)
Have you any tips to figure out this problem using a tableView ?
The way you lay out your cell now is fragile, because the order of painting the cells on screen matters a lot. Try moving the content up so that your buttons are flush with the top of the cell, and the time label fits into the cell entirely. Add a thin header view to your table to make the top cell appear normal. Keeping the content of a cell entirely within its bounds should help you maintain reasonable scrolling speeds.
EDIT : You could also put a second clipped label at the top of your cell, and make its content identical to that of the label in the prior row. You would need to take special care to hide that label in the top row, but otherwise this should make your table immune to changes in the rendering order of its cells.
Make the background color of your cell clear. As you scroll up the z ordering of your cells get reversed and the lower cells overlap the higher ones causing this clipping.

iPhone Dev - How to make a UITableView the exact height to fit all of the cells in it

I have the following:
I would like to make it so that the tableview stops right at the "So" cell, instead of having all the blank cells under it (the big plan is to have a bunch of multiple choice questions like the one in that pic, all on top of one another on one scrollview). I'm guessing I need to set the tableView's frame, but I was wondering if there was an easy way to calculate at runtime the exact height of the portion of the tableview where the cells are implemented (the ones with text in the pic). It's tricky because I made it so that each cell's height can change to accommodate the amount of text in it. Anyone have any advice?
There are two appproaches you can take.
Best and easiest.
1. Add a footer view to the table so it will not draw the rows after the last row. a blank footer view will do.
//Add empty view to hide trailing row seperators
UIView *emptyView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 0)];
emptyView.backgroundColor = [UIColor whiteColor];
[tableView setTableFooterView:emptyView];
[emptyView release];
2.Check how many rows you have in the tableview and calculate the tableheight and change the frame of table view.
There isn't a tableView:sizeOfAllCells: function if that is what you are looking for. From your question it sounds like you to adjust the size of your table so you can put other content on bottom of it.
You are correct is saying that you want to alter your UITableView's frame property to match the height.
[table setFrame:CGRectMake(0,0,table.frame.size.width,heightOfCells)];
There are a few things you could do though. If you had an array of all the cells, you could loop through it real quick and add the height of each of them. You could (I don't particularly recommend it though) loop though the number of sections and rows you have, using tableView:cellForRowAtIndex: instead of having an array of cells, and get the heights that way. If each cell is the same height (sounds like its possible it wont be) you could just do some simple math to figure out the height. Lastly, you could keep a dictionary or array of heights and update it in the tableView:cellForRowAtIndex: so if the content changes, it updates the size, but then you would have to call a reloadData. Those are just a few ideas of ways to solve this particular problem.
Here's a hack (so wait to see if a better solution comes along):
Use numberOfSections to get the number of sections (if you later change to grouped style), and then add up the heights of rectForSection: for each of the sections (in plain style, just take rectForSection:0). Maybe add a bit to this for the separators.

heightForRowAtIndexPath being called for all rows & how many rows in a UITableView before performance issues?

I thought I had read that for a UITableView that heightForRowAtIndexPath doesn't get called on all rows, but only on the ones that will be visible. This isn't what I'm seeing however. I'm seeing hundreds of calls to heightForRowAtIndexPath for the simple situation of the orientation being changed of the iPhone for example.
So I'm assuming here therefore that for a UITableView with heightForRowAtIndexPath implemented, it does (i.e. heightForRowAtIndexPath) get called for all rows (not just the visible ones)...let me know if this isn't quite correct.
QUESTION: Given the above, how many rows in a UITableView (where heightForRowAtIndexPath is implemented) can you have before performance issues occur typically?
Is there a way around the performance issues? i.e. set a nominal/standard height for each row and not implement heightForRowAtIndexPath, but then correctly set each row height only when it is displayed and set it correctly here...but which method would one do this in?
Have a look at the discussion section in the tableView:heightForRowAtIndexPath: documentation
The method allows the delegate to specify rows with varying heights. If this method is implemented, the value it returns overrides the value specified for the rowHeight property of UITableView for the given row.
There are performance implications to using tableView:heightForRowAtIndexPath: instead of the rowHeight property. Every time a table view is displayed, it calls tableView:heightForRowAtIndexPath: on the delegate for each of its rows, which can result in a significant performance problem with table views having a large number of rows (approximately 1000 or more).
So you should use the rowHeight property of the UITableView. If you need different heights you are out of luck because you have to use tableView:heightForRowAtIndexPath:.
AFAIK there is no way to change the row height at display.
The tableview has to know the correct size before, otherewise there would be ugly position shifts all the time.
I think I found a solution to that.
In iOS 7 apple introduced some new tableview properties. One of them is the:
tableView:estimatedHeightForRowAtIndexPath:
So if you supply an estimated row height, for example, then when tableView:heightForRowAtIndexPath: is called repeatedly before the table is displayed, it is called only for the visible cells of the table; for the remaining cells, the estimated height is used.
Here is the source for that information: https://books.google.gr/books?id=wLaVBQAAQBAJ&pg=PT521&lpg=PT521&dq=heightforrowatindexpath+only+for+the+visible+cells&source=bl&ots=7tuwaMT5zV&sig=h3q8AaFvoCgcrPu2fQchVkIEjwg&hl=en&sa=X&ved=0CEMQ6AEwBWoVChMInLK0xbPuxwIVCbUaCh3_nQWG#v=onepage&q=heightforrowatindexpath%20only%20for%20the%20visible%20cells&f=false
My goodness, I spent over an hour trying to find the source of my performance problem!
Finally I also found hundreds of calls to heightForRowAtIndexPath and a search
got me this thread. THAT is really annoying.
Performance goes down here already when just displaying 250 items. Thankfully the cells I want to display now all have the same size. But I could imagine someone wanting to display some different cells for a tableView with > 200 items!
FIX THIS APPLE!
Cheers
A way to improve performance in tableViews with a big number of rows and dynamic cell heights is to cache the height of the cells once they are first calculated.
A simplistic approach to achieve this is to keep a NSMutableDictionary in which the key is the id of the record in the cell (or any other identifier you might have), and the value is a NSNumber with the height of the row. Once the height is first calculated, store it the NSMutableDictionary by the record id. In the tableView:heightForRowAtIndexPath and tableView:estimatedHeightForRowAtIndexPath: you check for a cached height in the dictionary and return it if found. If not found, calculate the height, and store in the cache before returning the height.
You might have to be careful with invalidating the cache for the rows that change heights. For example, if you have an expand button in one of your cells, you will need to remove the height of that cell from cache once the expand button is tapped delegate method for height is called.
You might still have a performance hit if you try to display 1000 of cells at once when the table shows, as it will likely call the height method for each row. A work around for that is to first warm the cache, if possible in a background task, before first displaying the cells.

UITableView Did Load (Done drawing the cells)

Question
How can you detect when the Table View is done drawing the cells?
Issue
I got two labels within the contentView of an UITableViewCell. The size of these labels are dynamic. I was able to do so by subclassing UITableViewCell, in the drawRect method I adjust the frames of the two labels depending on their content. Now I want to align all the second labels.
My Thoughts in Steps
Determine the content in the table view and let it load automatically.
Run through the table view cells and determine the x position of the second label within the UITableViewCell that is the furtherest away.
Store this x position and when any cell is drawn use this x position to place the second label.
The problem is that if I use the following code:
for (int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++) {
UITableViewCustomCell *cell = (UITableViewCustomCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]];
NSLog ([cell.labelTwo description]);
}
The second label has not yet been drawn, meaning I can't determine the size of the frame and thus can not find the proper x position to align all second labels.
I have tried subclassing the UITableViewController and looking at events such as viewDidLoad and viewDidAppear unfortunatly also in these events the cells aren't drawn yet.
What I Want ...
What I want is for the table view to draw the cells at least once so I can determine the sizes of the labels within the table view cell. I thought to accomplish this by looping through all the cells with cellForRow, but although it successfully returns the cell the content is not drawn yet meaning the frame remains with a width of zero.
Does anyone have a solution?
Thanks in advance,
Mark
Try calling sizeWithFont: on the contents of these labels to get the max width before you draw anything. You should be able to use it later in your cellForRowAtIndexPath: to adjust the width as you need.
I would recommend you reconsider using UITableViewCellStyleValue2 cells instead and attempt to configure the textLabel and detailTextLabel. I had a similar situation and this is how I did it.
First off, you really ought to just pick an explicit, fixed position at which the first label ends and the second one begins, based on what you know about the minimum and maximum lengths of the text that will be put in those labels. That would eliminate this problem entirely.
But if you want a solution: use the sizeWithFont: method or one of its cousins (see the Xcode docs). Specifically, loop through the values that will go in the first labels, apply sizeWithFont to each, and keep track of the largest width you see. (I'm assuming you have access to the values before they go in the cells; since they're dynamic, they must be passing through the table view controller, no?)
Now you have the value you seek, without having to perform the extremely wasteful operation of creating a bunch of cell objects and never using them for their intended purpose.
I think what you need to do is to add a viewController to the have the UITableViewController control the UITableViewCell itself so that you can capture the events of the labels loading. The viewController will have references to both labels so it can adjust them accordingly in response to -viewDidAppear.
I've never done this but a UITableViewCell is a view like any other so you should be able to set up a controller for it. You might need to manually activate the controller since you have no navigation controller to do it for you in this context.