I have a UITableView nested within a UIScrollView and am finding it hard to calculate the height of either.
The content of both is dynamic so I'd like the tableview to expand to fit the content of it, and in turn the scrollview to expand to fit the content of the tableview.
I have this for the scrollview:
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in contentView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
But the resultant height is too long, too much scrolling.
The tableview I'm finding harder to get to dynamically resize, if I leave it without a defined size it is too small. So I added this:
self.tableView.contentSize = CGSizeMake(320.0f, [self.tableView contentSize].height);
And that's too big.
I think the size of the tableview is dictated by the number and height of the rows within it but can't find a clear answer here or on the net.
Any ideas?
Your UITableViewDelegate should implement:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
This will set the correct size for your cell.
I use the following code to set the height of UIScrollView:
for (UIView* view in scrollview_.subviews)
{
if (!view.hidden)
{
CGFloat y = view.frame.origin.y;
CGFloat h = view.frame.size.height;
if (y + h > scrollViewHeight)
{
scrollViewHeight = h + y;
}
}
}
[scrollview_ setContentSize:(CGSizeMake(320, scrollViewHeight))];
To get the height of UITableView, maybe you can calculate like rowheight*rowcount
Related
Currently, I've developed project that UIScrollView, UITableView, another 3 more UIView inputs and UIButton at the last. In that page, UIScrollView height will be dynamically increased based on height of UITableView.
For UITableView there is no more scrolling. Its height will be increased as well based on how many rows are added based on JSON data loaded by Async as follow.
productHeight = 44;
productHeight *= _nsOrderItems.count;
productHeight = productHeight + 100;
if (isHeaderTap) {
self.productTableHeight.constant = 50;
} else {
self.productTableHeight.constant = productHeight;
}
//then the tableView must be redrawn
[self.productTable setNeedsDisplay];
My Problem is I want to increase height of UIScrollView based on height of UITableView.
- (void)viewDidLayoutSubviews {
[self.scrollView setContentSize:CGSizeMake(_scrollView.frame.size.width, _btnEdit.frame.origin.y + _btnEdit.frame.size.height)];
}
You can definitely do that,
First make sure your constraint of cells subView must set to top to bottom in order to calculate the height required for the cell.
Make sure your delegated are set as below
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Set height constraint of your tableView and make outlet of that constraint.
Add below method to your class where you want to resize your tableView dynamically.
- (void)adjustHeightOfTableview
{
CGFloat height = self.tableView.contentSize.height;
//CGFloat maxHeight = self.tableView.superview.frame.size.height - self.tableView.frame.origin.y;
/*
Here you have to take care of two things, if there is only tableView on the screen then you have to see is your tableView going below screen using maxHeight and your screen height,
Or you can add your tableView inside scrollView so that your tableView can increase its height as much it requires based on the number of cell (with different height based on content) it has to display.
*/
// now set the height constraint accordingly
self.constraintHeightTableView.constant = height;
//If you want to increase tableView height with animation you can do that as below.
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];
}
Call this method when you are ready with the dataSource for the table, and call the method as
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
//In my case i had to call this method after some delay, because (i think) it will allow tableView to reload completely and then calculate the height required for itself. (This might be a workaround, but it worked for me)
[self performSelector:#selector(adjustHeightOfTableview) withObject:nil afterDelay:0.3];
});
// Get the supposed to be height of tableview
CGFloat height = self.tableViewMenu.contentSize.height;
// get the height constraint of tableview and give it you respected height
self.constraintHeightTableView.constant = height;
// set the scroll
NOTE:- don't forget to disenable the scrolling of table from storyboard or programmatically
self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, self.viewUserLogin.frame.size.height + height);
[self.scrollView layoutIfNeeded];
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);
}
I am using collection view for the first time and I'm not sure how to do something..
I have a UICollectionView with 12 cells. I set the collectView to scroll horizontally only and cells are lined up next to each other. I also turned on paging so I could use UIPageControll to indicate scrolling is active.
I want the collection view to only show four cells on the screen at any time. When the view loads, I get four cells, no problem. However when I scroll horizontally, I get 4 and a half cells. never just four.
Is there a way to tell the collection view only to show four cells at a time?
you can statically add number of cell(items)in collection view,if not require dynamic.
here I am using Scroll Direction Horizontal you can do it same way in vertical.
hope this will help
you can do this way also. Just copy this code into your view controller and make some changes.
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
NSIndexPath *indexPath;
for (UICollectionViewCell *cell in [self.collectionView visibleCells]) {
indexPath = [self.collectionView indexPathForCell:cell];
NSLog(#"%#",indexPath);
}
UICollectionViewCell *cell =(UICollectionViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
//finally get the rect for the cell
CGRect cellRect = cell.frame;
self.collectionView.contentOffset = CGPointMake(self.collectionView.contentOffset.x, cellRect.origin.y);
}
As Marc said, you could simply control the size of your collection view.
If changing the size is not practical, then you can set content inset on the collection view.
CGFloat cellWidth = … // Cell width
CGFloat collectionViewWidth = … // Collection View Width
CGFloat desiredCollectionViewWidth = cellWidth * 4.0;
CGFloat horizontalInset = collectionViewWidth - desiredCollectionViewWidth;
// To center the collection view
UIEdgeInsets inset = UIEdgeInsetsMake(0, horizontalInset/2, 0, horizontalInset/2);
self.collectionView.contentInset = inset;
// Or, to left justify the collection view
UIEdgeInsets inset = UIEdgeInsetsMake(0, 0, 0, horizontalInset);
self.collectionView.contentInset = inset;
I have added a search bar in a SectionHeader cell from the UICollectionView.
Currently I'm hiding the view by moving the Y-offset up.
[self.collectionView setContentOffset:CGPointMake(0, 44)];
This works perfectly when the height of my offset is bigger than my view. (vertical scrollbar)
But when the cells fit into my view, the search bar keeps still visible. (no vertical scrollbar)
Any idea?
Ty
What I did was subclass UICollectionViewFlowLayout and override the method:
- (CGSize)collectionViewContentSize {
CGSize size = [super collectionViewContentSize];
// add viewHeight to allow enough room for view to be hidden
if (size.height < self.collectionView.frame.size.height + viewHeight) {
size.height = self.collectionView.frame.size.height + viewHeight;
}
return size;
}
This does mean people can scroll a little bit on your collectionView when the size of the content is smaller than the bounds of your collectionView.
Sounds like you may just need to set alwaysBounceVertical:YES on your collectionView.
I have been working on this for about 2 days, so i thought i share my learnings with you.
The question is: Is it possible to make the width of a cell in a grouped UITableView smaller?
The answer is: No.
But there are two ways you can get around this problem.
Solution #1: A thinner table
It is possible to change the frame of the tableView, so that the table will be smaller. This will result in UITableView rendering the cell inside with the reduced width.
A solution for this can look like this:
-(void)viewWillAppear:(BOOL)animated
{
CGFloat tableBorderLeft = 20;
CGFloat tableBorderRight = 20;
CGRect tableRect = self.view.frame;
tableRect.origin.x += tableBorderLeft; // make the table begin a few pixels right from its origin
tableRect.size.width -= tableBorderLeft + tableBorderRight; // reduce the width of the table
tableView.frame = tableRect;
}
Solution #2: Having cells rendered by images
This solution is described here: http://cocoawithlove.com/2009/04/easy-custom-uitableview-drawing.html
I hope this information is helpful to you. It took me about 2 days to try a lot of possibilities. This is what was left.
A better and cleaner way to achieve this is subclassing UITableViewCell and overriding its -setFrame: method like this:
- (void)setFrame:(CGRect)frame {
frame.origin.x += inset;
frame.size.width -= 2 * inset;
[super setFrame:frame];
}
Why is it better? Because the other two are worse.
Adjust table view width in -viewWillAppear:
First of all, this is unreliable, the superview or parent view controller may adjust table view frame further after -viewWillAppear: is called. Of course, you can subclass and override -setFrame: for your UITableView just like what I do here for UITableViewCells. However, subclassing UITableViewCells is a much common, light, and Apple way.
Secondly, if your UITableView have backgroundView, you don't want its backgroundView be narrowed down together. Keeping backgroundView width while narrow down UITableView width is not trivial work, not to mention that expanding subviews beyond its superview is not a very elegant thing to do in the first place.
Custom cell rendering to fake a narrower width
To do this, you have to prepare special background images with horizontal margins, and you have to layout subviews of cells yourself to accommodate the margins.
In comparison, if you simply adjust the width of the whole cell, autoresizing will do all the works for you.
To do this in Swift, which does not provide methods to set variables, you'll have to override the setter for frame. Originally posted (at least where I found it) here
override var frame: CGRect {
get {
return super.frame
}
set (newFrame) {
let inset: CGFloat = 15
var frame = newFrame
frame.origin.x += inset
frame.size.width -= 2 * inset
super.frame = frame
}
}
If nothing works you can try this
Make the background colour of the cell as clear color and then put an image of the cell with required size. If you want to display some text on that cell put a label above the image. Don't forget to set the background color of the label also to clear color.
I found the accepted solution didn't work upon rotation. To achieve UITableViewCells with fixed widths & flexible margins I just adapted the above solution to the following:
- (void)setFrame:(CGRect)frame {
if (self.superview) {
float cellWidth = 500.0;
frame.origin.x = (self.superview.frame.size.width - cellWidth) / 2;
frame.size.width = cellWidth;
}
[super setFrame:frame];
}
The method gets called whenever the device rotates, so the cells will always be centered.
There is a method that is called when the screen is rotated : viewWillTransitionToSize
This is where you should resize the frame. See example. Change the frame coords as you need to.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[coordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
int x = 0;
int y = 0;
self.tableView.frame = CGRectMake(x, y, 320, self.tableView.frame.size.height);
}];
}
i do it in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
CGFloat tableBorderLeft = self.view.frame.origin.x + 10;
CGFloat tableBorderRight = self.view.frame.size.width - 20;
CGRect tableRect = self.view.frame;
tableRect.origin.x = tableBorderLeft;
tableRect.size.width = tableBorderRight;
tableView.frame = tableRect;
}
And this worked for me
In .h file add the delegate 'UITableViewDataSource'
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return size;
}