Change height of the "header view" inside UITableView - ios

I added a view "Header View" inside a table view (see structure in screenshot). It has fixed height. I tried to change view's frame size, view is getting smaller, but there is still empty space between header and tableview cells.
I need to change header height dynamically in code. Any suggestions?

I suggest you move the Header View out as a subview of View, set a tag to it, then in viewForHeaderInSection, use the tag to get it. Set the proper height in heightForHeaderInSection. When height changes, refresh tableView. The reason for that is Header View is no longer a subview of the table view, it will always stick to the first table view row.
Also with the current design you can make the Header View a cell, then in the viewForHeaderInSection you can reuse the cell, if you have multiple sections this is the way to go.

In your tableview's delegate, you have to use
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return /*desired height*/;
}
EDIT
According to your comment, if you don't want to change your interface, what you can do is to set a height constraint to that view.
You then make a reference of the constraint to the header of the controller managing the view.
In the code, you can then change the height by changing the value of the constraint and updating the view :
[UIView animateWithDuration:/*animation time in seconds*/ animations:^{
yourHeightConstraint.constant = /*desired height*/;
[self.view layoutIfNeeded];
}];
[self.view updateConstraints];

Related

Getting collection view cells to update after a constraint change

I'm having a problem with auto layout in a collection view cell in iOS 9.
During the collection view's :cellForItemAtIndexPath: I change a constraint:
[[self rootStack] setDistribution:UIStackViewDistributionFillEqually];
or
[[self rootStack] setDistribution:UIStackViewDistributionFillProportionally];
During the cell's preferredLayoutAttributesFittingAttributes: I try to force an additional round of layout:
- (UICollectionViewLayoutAttributes*) preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
{
[self setNeedsLayout];
[self layoutIfNeeded];
return layoutAttributes;
}
Still, when cells are displayed, some show the effect of the constraint change and some do not. If I scroll a cell that does not display the change offscreen and then scroll back to it, it then displays the change. Moving the constraint changes to the cell's updateConstraints resulted in none of the cells showing the change on first display.
I can fix this for the first cells that are displayed by calling reloadData on the collection view during the collection view controller's viewWillAppear:. But once I start scrolling some of the cells that come into view are not formatted correctly (unless I scroll past them and then scroll back to them).
Is there a way I can make sure that all cells are formatted correctly the first time they are displayed?

Custom UIView(.xib) changes frame automatically after adding as subview in UITableViewCell

Due to requirement, I have made a custom UIView with .xib. The problem is when i alloc,init the uiview , the frame is all right but when i add the view as subview to UITableViewCell.contentView, the frame of my custom view dramatically changes. I even tried to enforce the frame after adding as subview but of no help.
I am using storyBoard with autolayout. the problem persists in both case when i set constrains in my custom view and when remove all constrains .
Thanks in advance.
So your issue is that you are not changing height of row when your adding view into your cell's content view. Here is below height method and changes that you need to implement:-
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if((indexPath.row==3 && rowSelected)) //You need to put condition check in which you need to see if that particular row is selected or not.
//Then a flag for checking if view is added or not to it's contentView.
//If both condition true then you need to provide a new height to that particular cell.
return 220; //120 height of your cell + 100 height of your view.
else
return 120;
}

objc xcode setting y start position of uitableview cells when there is other content above with flexible size

I have a question about the usage of UITableView. I have added a UIView above the cells of my UITableView (see image).
This is very nice because I can add some images and labels there and it will scroll with the cells of the table view. Now I am calling some REST API to get an image which I want to add in this view above the cells. The problem now is that I dont know the height of the image, so I have to calculate it based on the aspect ratio which already works fine. When I add the image I can change its height correctly and move down labels and buttons BUT the image overlaps some of the visible cells.
My question: How can I move down the frame of the container? of the cells? dynamically based on my image respective View height?
I have tried to set the height of the View in the TableView but it has no effect. So I suppose that I have to set the y start position of the cells but I dont know how.
Do I need to set an y offset in the delegate method -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath ?
Any ideas?
I think the key to this is setting your view to be the table view's tableHeaderView after you change the size of the view. I did it like this in a test app,
-(void)layoutHeader {
self.label.text = #"This is a long text to see if it expands to take up multple lines. The quick red fox jumped over the lazy brown dog.";
[self.label setPreferredMaxLayoutWidth:self.tableView.frame.size.width];
CGRect stringRect = [self.label.text boundingRectWithSize:CGSizeMake(self.tableView.bounds.size.width - 40,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:self.label.font} context:nil];
CGRect headerFrame = self.header.frame;
headerFrame.size.height = stringRect.size.height + 40;
self.header.frame = headerFrame;
[self.tableView beginUpdates];
self.tableView.tableHeaderView = self.header;
[self.tableView endUpdates];
}
I called this with a delay from viewDidLoad as a test. The beginUpdates, endUpdates code isn't necessary if you don't want to see the rows move down to accommodate the new view size. The property, header, is an IBOutlet to the view I added to the top of the table view in IB, and "label" is a subview of that view.
I would personally just use tableView:viewForHeaderInSection: to build the view out, and in tableView:heightForHeaderInSection: calculate the new height and return that. That way you don't have to worry about bumping things down within the tableView since UITableView will handle the rest for you once you. Just make sure to call [_tableView reloadData]; on your tableView after you get the image.

Scrolling ViewController Content

What I have in the view controller view are :
An image of fixed height
Few labels
Table view with n rows.
Once rendered I want everything here to be inside the scroll the view so the user can scroll the entire screen as needed. Note that the scrollView needs to expand to the entire size of the tableView to show its full contents. I have tried different ways of doing this but unable to do it. I would appreciate any pointers or code segment to get this done.
There are essentially two ways to do so.
tableHeaderView
The first way involves the tableHeaderView property of the UITableView instance you have. You can simply add the UITableView with the constraints/frame/autoresizingMask that allows you to put it full-screen. Done that, you simply do (i.e. in your viewDidLoad):
UIView *headerView = [UIView new];
// Here I am supposing that you have a 200pt high view and a `self.tableView` UITableView
headerView.frame = CGRectMake(0, 0, self.tableView.frame.size.width, 200.0);
UIImageView *fixedImageView = [UIImageView new];
// configure your imageView..
[headerView addSubview:fixedImageView];
// configure labels as you want and add them to headerView as subviews
// Now set `UITableView` headerView
self.tableView.tableHeaderView = headerView;
If you want to use AutoLayout for your tableHeaderView, I suggest you to take a look at this question
Dynamic scrollView
Another way to do this is to to create an UIScrollView, put everything inside, and let it scroll. The downside of this method is that if you are using floating section headers for your UITableView, they will not float due to the fact that the tableView is going to stay fixed, while the parent scrollView is going to scroll.
On the other side, this approach is more AutoLayout friendly due to the fact you can use constraints easily.
To do so, you start adding an UIScrollView to your view, and placing all your other views inside it.
Be sure to add a Vertical Spacing constraint between the first view inside your scrollView (I suppose the UIImageView) and the scrollView top, and between the last view (I suppose the UITableView) and the scrollView bottom, to avoid an ambiguous content size.
You should have something like that (I omitted the labels for the sake of brevity):
Note that every view is inside a parent UIScrollView
After that, add an Height constraint to the tableView, and add an IBOutlet to your view controller subclass, i.e. like this:
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeightConstraint;
Now you only need to configure this constraint to reflect the tableView natural height, given by its rows, etc. To do so, you simply calculate the height in this way:
// Resize TableView
CGFloat height = self.tableView.contentSize.height;
self.tableViewHeightConstraint.constant = height;
Now the tableView will resize, and due to its constraints it will adapt the parent scrollView contentSize.
Just be sure to refresh this height constraint anytime you reload the UITableView dataSource.

TextField subview not resizing w/ UITableViewCell frame size change

Have a storyboard w/ a TableViewController that has a grouped table view. In the first section, I want the cells' width to be smaller than full-screen. To accomplish the latter, I have a custom UITableViewCell class w/ the following method:
- (void)setFrame:(CGRect)frame {
frame.origin.x += NAME_TABLE_VIEW_INSET;
frame.size.width -= NAME_TABLE_VIEW_INSET;
[super setFrame:frame];
}
That works fine. The issue I have is that a UITextField subview that I dragged into the storyboard cell does not adjust its width automatically to the new cell frame size.
I've tried sub-classing UITextField and ensuring that the autoResizingMask is set properly, and I've tried using [super layoutSubviews] in the setFrame method above. None of these approaches works.
Any suggestions on how I can get the text field to adjust its width automatically while still using this storyboard approach?
The solution for this was to add a separate table view in the header of the tableView provided by the table view controller. Specifically, add a view object to the top of the table view in IB; add a table view as a subview into that view; change the width of the new table view's cells.
Note that this problem exists only because I wanted to use a table view controller, which defaults each cell to the width of the screen. A view controller could have been used, but then you cannot add a table view w/ static cells as a subview.

Resources