to correctly embed a UITableView into a UIScrollView I need to know the exact height of the UITableView. I added the count of rows * rowHeight and the count of section headers * sectionTitleHeight, but this is still roughly 50px off the point. I guess it is caused by the empty table header and footer, but I can't find any information about how high they are...
Did I miss something in the UITableView class ref?
Thanks for any tips,
nobi
You can get the UITableView's frame variable and check its size member variable to see the exact size of your UITableView element.
CGSize tableSize = [table frame].size;
CGFloat tableHeight = tableSize.height;
CGFloat tableWidth = tableSize.width;
Related
I have an UITableView (aka. ParentTableView) with multiple UITableViewCell's. Each UITableViewCell contains some labels and an UITableView (aka. ChildTableView).
The ChildTableView's rows have different amounts of UITableViewCells.
There is two things I need help to figure out.
1. The height of the ChildTableView should be the height of its contents. So there should be no scroll on this tableview. It's basically just a list.
2. Set the ParentTableView's row height to: (default height + ChildTableView's calculated height from question 1)
After tableView finishes loading cells ( gets its content ) update the Frame of the TableView with the Content Size.
so after reloadData:
var bounds = tableView.bounds
bounds.size.height = tableView.contentSize.height
// You can add anything to the height now with bounds.size.height += something
tableView.bounds = bounds
You can also explicitly disable the scrolling with scrollEnabled = false
This is my ViewController in the storyboard:
UIView (Controller)
-UIScrollView
--UIView
--UIView
--ContainerView
---UITableView (Embedded inside ContainerView)
The UITableView has dynamic prototypes.
My question is how do I change the UIScrollView and ContainerView's height to adapt to the UITableView's number of rows?
I want to be able to scroll down with my UIScrollView(not the UITableView's UIScrollView), when there are many rows inside the UITableView.
You can apply below logic to increase the height of scroll view.
height = Total number of rows (array or dictionary count) * your cell height (cell height should be static).
Using below calculation you will find the total height and set this height as a table height or scroll view height.
[scrollview setContentSize:CGMakeSize(scrollview.contentSize.width,tableView.frame.size.height)];
OR
[scrollview setContentSize:CGMakeSize(scrollview.contentSize.width,height)];
I hope this is work for you.
Thanks
Just update the contentSize of the UIScrollView every time there is a change in the number of rows.
Look at the example below:
- (void)updateScrollViewContentSize
{
float cellHeight = 40;
int numberOfRows = [noOfItemsInArray count];
float sizeOfContent = cellHeight * numberOfRows;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent);
}
In my UIViewController I have dragged a UITableView which has 2 custom Prototype Cells. Basically Its a accordion.
When I am loading data on it there always a gap coming between my table view starting position and first row. when I scroll down Its working fine.I have searched in google and find couple of suggestion like
put
self.automaticallyAdjustsScrollViewInsets = YES;
In viewDidLoad OR add This below code in
UIEdgeInsets insets = UIEdgeInsetsMake(self.topLayoutGuide.length,
0.0,
self.bottomLayoutGuide.length,
0.0);
_detailsTableView.contentInset = insets;
or
YouStoryboard.storyboard > YouViewController > Attributes inspector > Uncheck - Adjust scroll view insets
But none of this worked for me. Here is my UITableView screenshot. Please suggest that how I can remove this gap marked in red.
After fixing this issue UITableView should looks like
Inspector Image 1
Try implementing this method:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
CGFloat height = UITableViewAutomaticDimension;
if (section == 0) {
height = 0.5f;
}
return height;
}
This will remove the spacing for the first section header. If you want to remove all spacings between sections you can always return 0.5f. Such an odd value is needed because Apple does not allow you to return 0 in this method. (That would have the same effect as not implementing the method at all.) But the value 0.5f will have the desired effect.
I think the space you are trying to get rid of is the header. Use the tableview delegate to set the header on section 0 to a height of 0.
tableView:heightForHeaderInSection
I have a UITableViewCell subclass which has an image, title and description.
I am supposed to resize the cell height according to the description content length i.e. if it spans more than 5 lines, I should extend it (+other subviews like image etc) till it lasts.
The next coming cells should begin only after that.
I have my UITableViewCell subclass instantiated from xib which has a fixed row height = 160.
I know this is pretty standard requirement but I am unable to find any guidelines.
I already extended layoutSubViews like this:
- (void) layoutSubviews
{
[self resizeCellImage];
}
- (void) resizeCellImage
{
CGRect descriptionRect = self.cellDescriptionLabel.frame;
CGRect imageRect = self.cellImageView.frame;
float descriptionBottomEdgeY = descriptionRect.origin.y + descriptionRect.size.height;
float imageBottomEdgeY = imageRect.origin.y + imageRect.size.height;
if (imageBottomEdgeY >= descriptionBottomEdgeY)
return;
//push the bottom of image to the bottom of description
imageBottomEdgeY = descriptionBottomEdgeY;
float newImageHeight = imageBottomEdgeY - imageRect.origin.y;
imageRect.size.height = newImageHeight;
self.cellImageView.frame = imageRect;
CGRect cellFrame = self.frame;
cellFrame.size.height = imageRect.size.height + imageRect.origin.y + 5;
CGRect contentFrame = self.contentView.frame;
contentFrame.size.height = cellFrame.size.height - 1;
self.contentView.frame = contentFrame;
self.frame = cellFrame;
}
It pretty much tells that if description is taller than image, we must resize the image as well as cell height to fit the description.
However when I invoke this code by doing this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.cellDescriptionLabel.text = #"Some long string";
[cell.cellDescriptionLabel sizeToFit];
[cell setNeedsLayout];
return cell;
}
It appears that while cell frame is changed due to layoutSubViews call, other cells do not respect it. That is, they appear on the same position had the previous cell would not have resized itself.
Two questions:
How to make it possible what I want?
Am I doing right by calling setNeedsLayout within cellForRowAtIndexPath?
P.S.: I know heightForRowAtIndexPath holds key to changing the cell height, but I feel that the data parsing (not shown here) that I do as part of cellForRowAtIndexPath would be an overkill just to calculate height. I need something that can directly tell the UITableViewCell to resize itself according to content needs.
-tableView:heightForRowAtIndexPath: is by design how variable sized cells are calculated. The actual frame of a cell is of no importance and is changed by the table view to fit its needs.
You are sort of thinking of this backwards. The delegate tells the table view how cells need to be drawn, then the table view forces cells to fit those characteristics. The only thing you need to provide to the cell is the data it needs to hold.
This is because a table view calculates all the heights of all the cells before it has any cells to draw. This is done to allow a table view to size it's scroll view correctly. It allows for properly sized scroll bars and smooth quick-pans through the table view. Cells are only requested when a table view thinks a cell needs to be displayed to the screen.
UPDATE: How Do I Get Cell Heights
I've had to do this a couple of times. I have my view controller keep a cell which is never used in the table view.
#property (nonatomic) MyTableViewCell *standInCell;
I then use this cell as a stand in when I need measurements. I determine the base height of the cell without the variable sized views.
#property (nonatomic) CGFloat standInCellBaseHeight;
Then in -tableView:heightForRowAtIndexPath:, I get the height for all my variable sized views with the actual data for that index path. I add the variable sized heights to my stand in cell base height. I return that new calculated height.
Note, this is all non-autolayout. I'm sure the approach would be similar, but not identical to this, but I have no experience.
-tableView:heightForRowAtIndexPath: is the preferred way to tell tableview the size of its cells. You may either precalculate and cache it in a dictionary and reuse, or alternatively in ios7, you can use -tableView:estimatedHeightForRowAtIndexPath: to estimate the sizes.
Take a look at this thread - https://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights, the answer points to a very good example project here - https://github.com/caoimghgin/TableViewCellWithAutoLayout.
Sorry, but as far as I know you have to implement tableView:heightForRowAtIndexPath:. Warning, in iOS 6 this gets called on every row in you UITableView right away, I think to draw the scrollbar. iOS7 introduces tableView:estimatedHeightForRowAtIndexPath: which if implemented allows you to just guess at the height before doing all the calculation. This can help out a lot on very large tables.
What I found works well is just have your tableView:heightForRowAtIndexPath: call cellForRowAtIndexPath: to get the cell for that row, and then query that cell for it's height cell.bounds.size.height and return that.
This works pretty well for small tables or in iOS7 with tableView:estimatedHeightForRowAtIndexPath implemented.
I have a UITableView that is set to not enable scrolling, and it exists in a UIScrollView. I'm doing it this way as the design specs call for something that looks like a table view, (actually there are two of them side by side), and it would be much easier to implement tableviews rather than adding a whole bunch of buttons, (grouped table views).
Question is, I need to know how big to make the container view for the scrollview, so it scrolls the whole height of the table views. Once loaded, is there any way to find the height of a tableview? There is no contentView property like a scroll view, frame seems to be static, etc...
Any thoughts?
Use
CGRect lastRowRect= [tableView rectForRowAtIndexPath:index_path_for_your_last_row];
CGFloat contentHeight = lastRowRect.origin.y + lastRowRect.size.height;
You can then use the contentHeight variable to set the contentSize for the scrollView.
A more general solution that works for me:
CGFloat tableViewHeight(UITableView *tableView) {
NSInteger lastSection = tableView.numberOfSections - 1;
while (lastSection >= 0 && [tableView numberOfRowsInSection:lastSection] <= 0)
lastSection--;
if (lastSection < 0)
return 0;
CGRect lastFooterRect = [tableView rectForFooterInSection:lastSection];
return lastFooterRect.origin.y + lastFooterRect.size.height;
}
In addition to Andrei's solution, it accounts for empty sections and section footers.
UITableView is a subclass of UIScrollView, so it has a contentSize property that you should be able to use no problem:
CGFloat tableViewContentHeight = tableView.contentSize.height;
scrollView.contentSize = CGSizeMake(scrollView.contentSize.width, tableViewContentHeight);
However, as several other SO questions have pointed out, when you make an update to a table view (like inserting a row), its contentSize doesn't appear to be updated immediately like it is for most other animated resizing in UIKit. In this case, you may need to resort to something like Michael Manner's answer. (Although I think it makes better sense implemented as a category on UITableView)
You can run over the sections and use the rectForSection to calculate the total height (this included footer and header as well!). In swift I use the following extension on UITableView
extension UITableView {
/**
Calculates the total height of the tableView that is required if you ware to display all the sections, rows, footers, headers...
*/
func contentHeight() -> CGFloat {
var height = CGFloat(0)
for sectionIndex in 0..<numberOfSections {
height += rectForSection(sectionIndex).size.height
}
return height
}
}