When reloadData gets called, it seems that the UITableView recalculate its contentSize automatically so that the content will fit (see screenshot of the call stack in Xcode). How do I stop that?
I want to have the contentSize to be bigger than its content in some cases, when the table is partly obscured. But any changes of the contentSize will disappear after reloading.
You need to change the contentSize of UITableView after every "reloadData" call, you can do this :
[self.tableView reloadData];
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height < 44 ? 150/*any desired value you like*/ :self.tableView.contentSize.height);
I solved it by using contentInset instead, like this:
float extraSpaceAtTheBottom = 50;
self.tableView.contentInset = UIEdgeInsetsMake(0.0, 0.0, extraSpaceAtTheBottom, 0.0);
Set a layout constraint for height on the tableView.
Related
I have a UITableView with a UIView on top. I want the UIView to stick to the top as the tableView cells scroll over it.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.tableView.contentOffset.y > 0) {
CGRect newframe = self.publicTopView.frame;
newframe.origin.y = -self.tableView.contentOffset.y;
self.publicTopView.frame = newframe;
NSLog(#"After: %f", self.publicTopView.frame.origin.y);
}
}
You need to set your table view header view to the view you want on top.
Add this code to you viewDidLoad
self.tableView.tableHeaderView = self.publicTopView
I'm not certain what you're trying to accomplish, but I have a guess at what is wrong. As you scroll your contentOffset will continue to change and let's say your tableView has a content size height of 1500, then your contentOffset will eventually be larger than the height of your view controllers view. Now see that you are putting that contentOffset into the origin.y of your publicTopView. So your publicTopView could possibly be moving too much, even offscreen depending on how large your tableview's content size is.
I have got an UIViewController containing an UIScrollView. Initially automaticallyAdjustsScrollViewInsets is not set (so it should default to YES).
On some user interaction I set automaticallyAdjustsScrollViewInsets to NO, so I can set my own contentInset on the scroll view.
After doing so nothing happens. What do I have to call afterwards?
Calling setNeedsDisplay on the scroll view doesn’t help.
If you want your initial display of your scrollview to include an initial content offset, then set the contentInset value in viewDidLoad.
If you wish to dynamically change the contentInset and have the contentOffset change as well, then you need to adjust the contentOffset at the same time as the contentInset. For example:
// Adjust content inset and initial offset to account for the header
UIEdgeInsets contentInset = self.collectionView.contentInset;
contentInset.top += self.stickyHeaderView.bounds.size.height;
self.collectionView.contentInset = contentInset;
if (-1 * self.collectionView.contentOffset.y < contentInset.top) {
CGPoint contentOffset = self.collectionView.contentOffset;
contentOffset.y = -1*contentInset.top;
[self.collectionView setContentOffset:contentOffset animated:YES];
}
In a UIViewController on a storyboard, I have a UITableView that is sized specifically to have two rows in one section with no header or footer, i.e. the height is 88.0f. There are some cases when I want to add a third row. So in viewWillAppear:animated: (and other logical places) I set the frame to be 44.0f logical pixels higher:
CGRect f = self.tableView.frame;
self.tableView.frame = CGRectMake(f.origin.x, f.origin.y, f.size.width, f.size.height + 44.0f);
NSLog(#"%#",NSStringFromCGRect(self.tableView.frame));
Nothing controversial; pretty standard resize code, and yet... It doesn't work! The tableView height doesn't change visually. The NSLog statement reports the height I expect (132.0f). Is this because I'm using Storyboards? I'm not sure why this isn't working.
Set an auto layout constraint for the height of the table view in your storyboard. Then connect the constraint to an outlet in your view controller so you can access the constraint in your code. Have the constraint be set to 88. When you want to change the height of the table view, just change the constraint's constant to 132.
You can modify the frame only after the call to layoutSubviews is made, which occurs after viewWillAppear. After layoutSubviews is called on the UIVIew you can change the dimensions.
As Gavin suggests, if you have the autolayout enabled you can add the constrains to the UITableView via storyboard, connect the height constraint and modify its value as follow:
constraint.constant = 132.0f
Otherwise if you have the autolayout disabled you can simply change the frame updating the height, but putting the code in a different method, for example viewDidLoad:.
recently I'm try to do what you've do. And I got same problem, tableview height won't change. Now I got the solution, you need to call layoutSubviews after change the frame. And it work on me.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
tableView.frame = CGRectMake(tableView.frame.origin.x, tableView.frame.origin.y, tableView.frame.size.width, tableView.frame.size.height + 44.);
[tableView layoutSubviews];
}
don't place it in viewDidLoad or viewWillAppear: because even layoutSubviews is called, the frame won't change. place it on viewDidAppear:
I know how to animate the height change of a UITableViewCell using the method seen here: Can you animate a height change on a UITableViewCell when selected?
However, using that method, the UITableView will scroll at the same time, which I don't want it to do.
I have a UITableView with very few cells; it takes up less than the screen height. The bottom cell has a UITextField and, when it starts editing, I manually set the content offset of the UITableView so that the cell with the UITextField is scrolled to the top. Then, based on the input in the UITextField, I may want to increase the size of the UITableViewCell to show extra options, more or less.
The problem is that, when animating this change, it will reposition the UITableView so that my UITextField is no longer at the top.
This is what I'm doing, more or less:
self.customAmountCellSize = height;
[self.tableView beginUpdates];
[self.tableView endUpdates];
I have also tried
self.customAmountCellSize = height;
CGPoint originalOffset = self.tableView.contentOffset;
[self.tableView beginUpdates];
[self.tableView endUpdates];
[self.tableView setContentOffset:originalOffset animated:NO];
I want the row height animation, I do not want the UITableView to scroll as a result.
Any ideas?
It appears the problem you're encountering is that your table view is scrolled past the bottom so when you update its content it will attempt to fix that.
There are two approaches you could take to prevent scrolling:
Set the table view's content inset to be the height of the initial white space:
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, verticalGap, 0);
Add an empty footer view with the same height as the vertical gap:
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, verticalGap)];
In both cases, you will need to calculate the vertical space you are trying to achieve. You then need to restore the contentInset or tableFooterView to its original state when you are done.
I think the table view is scrolling because your text field is becoming the first responder, and not because of the cell height change. Try keeping the cell height the same and just adjusting the offset to be sure.
If I am correct, than here's the solution: UITableView automatically tries to scroll when your keyboard appears. To fix this, set the content offset to your desired offset in a dispatch to the main queue, which will fire at the beginning of the next runloop. Put the following code inside your response to a UIKeyboardWillShowNotification, or in a UITextFieldDelegate shouldBeginEditing method:
// Get the current offset prior to the keyboard animation
CGPoint currentOffset = self.tableView.contentOffset;
UIEdgeInsets currentInsets = self.tableView.contentInset;
__weak SomeTableViewControllerClass *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animationWithDuration:0 animations:{
// set the content offset back to what it was
weakSelf.tableView.contentOffset = currentOffset;
weakSelf.tableView.contentInset = currentInsets;
} completion:nil];
});
Similar fixes are sometimes necessary for the contentInset.bottom of a table view, depending on the frame of your UITableView and other factors.
I need to get the full height of a UITableView (i.e. the height at which there would be nothing more to scroll). Is there any way to do this?
I've tried [tableView sizeThatFits:CGSizeZero], but that only returns a 0x0 CGSize.
Try the contentSize method, which is inherited from UITableView’s superclass, UIScrollView. However, you may find that contentSize returns an incorrect or out of date value, so you should probably call layoutIfNeeded first to recalculate the table’s layout.
- (CGFloat)tableViewHeight
{
[tableView layoutIfNeeded];
return [tableView contentSize].height;
}
Obligatory Swift 3.0 & 2.2 answer.
var tableViewHeight: CGFloat {
tableView.layoutIfNeeded()
return tableView.contentSize.height
}
Try passing in a different CGSize parameter instead of CGSizeZero. The sizeThatFits: method uses that parameter to calculate its result. Try passing in self.view.size from whatever class is making that call.
If a table view rows count changed and you indeed need to know the content size of table view incorporating the last changes, I didn't find that layoutIfNeeded method actually helps.
After a little bit hacking, I get to know how to force table view recalculate its content size. In my case, it is enough to reset table view frame to get it working:
- (CGSize)com_lohika_contentSize
{
CGRect theFrame = self.frame;
self.frame = CGRectZero;
self.frame = theFrame;
[self layoutIfNeeded];
return [self contentSize];
}