I have a table view as part of a larger controller. This table view can have various number of rows and rows are expandable (e.g. unselected state is 50pt, selected -> 120pt).
To animate sell expanding/collapsing I use those methods:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.beginUpdates()
tableView.endUpdates()
view.setNeedsLayout()
view.layoutIfNeeded()
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.beginUpdates()
tableView.endUpdates()
view.setNeedsLayout()
view.layoutIfNeeded()
}
But I need to update container view height in parent view controller together with the table view.
I've tried to achieve that by adding observer to the contentSize of the tableView and assigning its height to the containerView height constraint. Its kinda work but animation of the containerView height happens after cell increase/decrease animation already happened.
Is there a way to achieve dynamic height table view in embedded view controller?
PS. I don't want to use table view footer/header to put surrounding views there as surrounding view structure is more complex and table view is just part of it.
Related
I'm using this code in cellForRowAt :
cell.frame = tableView.bounds
cell.layoutIfNeeded()
collectionView.reloadData()
heightConstraint.constant = collectionView.collectionViewLayout.collectionViewContentSize.height
and
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
This works at the first time, but when I load more items to collection view it doesn't work unless I use tableView.reloadData()
But when I use tableView.reloadData() scrolling stops for a second, and I want it to flow without freezing.
Anyone has a solution? Thanks in advance.
You can reload only the cell that you are updating in case you don't want to reload the table
tableView.reloadRows(at: [IndexPath], with: .none)
Any time you change a cell height after it has been displayed, you need to tell the table view about it.
You haven't shown how or when you "load more items to collection view" ... but after you do that, call:
tableView.performBatchUpdates(nil, completion: nil)
That will cause the table view to recalculate and update the row heights, without calling .reloadData().
i have table view inside table view cell, need to set table view height depending on table view content, i tried below code
extension tableViewCell: UITableViewDelegate{
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
lcOptionsTVHeight.constant = tableView.contentSize.height
}
}
}
but this is not working in first load, but updating as i do scroll up and down, how can do load in properly in first load itself?
heightForRowAt(:)
You need to pass your height in heightForRowAt(:)
In this method, you need to check if it's the nested tableview cell and return the height, in other cases just return UITableView.automaticDimension
My suggestion would be to use sections instead of nested tableview. Only if there's horizontal scrolling requirement(not the case here as you mentioned tableview inside a tableview cell), we can go with a collectionview inside tableview cell.
Here, using different sections might be sufficient. You can reload sections by tableView.reloadSections
Again it might be dependent on your requirement. In general, we don't see tableview inside a tableview cell.
I'm looking for a way to resize a tableView cell with a more complex layout.
To simplify the description of the problem the tableview cell consists of three views. One view that defines the "background" of the cell and two additional views (each of them with a height 45% of the background cell.
One of these additional views is tagged to the top of the background view the other one to be bottom.
If the user taps on the tableview cell it should shrink in a way that only the top view is visible and after an additional user tap it should resize to its full size again.
The user tap is handled by the function
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
and the resizing is done by
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
Unfortunately, after shrinking the tableview cell, both addition views are displayed with half of their original hight.
var selectedCell = -1
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
if (selectedCell != indexPath.row)
{
selectedCell = indexPath.row
}
else {
selectedCell = -1
}
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (indexPath.row == selectedCell)
{
return 65
}
else {
return UITableView.automaticDimension
}
}
I'm now looking for a way to change the code in a way, that after shrinking only the upper view is visible.
Example picture of the fully visible cell
In the example picture, after shrinking the tableview cell should only display the red view.
Thanks in advance
Patrick
The reason is that when the cell is shrunk, your views (since their sizes are defined relative to parent's size) also gets shrunk and are visible with half size. They are not really gone/hidden from the view. What you need is to hide/remove them from the view.
It looks from your description that you are using plain constraints to achieve this. This can be done by just using constraints but its a lot more work. So I will mention two ways to get this done:
Using just constraints
When the user taps your cell, you need to make the height of the bottom view 0. Also, if you do not want the middle 10% part to show when the cell shrinks, you would need to create an additional constraint from the bottom of the top view to the bottom of the contentView of the cell. Similarly, your bottom view will also have two height constraints, one for 45% and one for 0.
The idea is to have both these constraints at the same time but with different priorities. The initial constraint will have higher priority and the other one will have a lower priority. Although these constraints will be contradictory, iOS will take the higher priority one to render the view.
Next, you would need to toggle the active property of the higher priority constraint on user tap which will in turn let iOS use the lower priority constraint to render the view.
Use stackview:
iOS 9 introduced stack view which is a helper view. It basically, handles constraints for you, at least some part of it. When you hide one view from the stack view's children, stack view will automatically make the height of that view to be 0. read up more about vertical stack view and you will get the idea.
I have a design, where UITableView is in UIScrollView with other content and the content is scrolling with the table data. It means, that table has scrolling disabled and is stretched to full size.
I'm using autolayout and the table has height constraint, set to some default value.
Then I have overwritten viewWillLayoutSubviews method:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if (self.itemTableView.contentSize.height > 0) {
self.itemTableViewHeightConstraint.constant = self.itemTableView.contentSize.height
}
}
With this method in place, when I called self.itemTableView.reloadData() after loading the data from the REST, the height constraint was set to table content height, which was great.
This used to work for me in many projects, but for some reason it is not working in the latest one, written in swift 4. Does something changed? Why tableView reloadData() method does not invoke viewWillLayoutSubviews()?
The problem was that the tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) was not calling self.view.setNeedsLayout() before returning row.
I have multiple tableviews in my ViewController and each tableview has different number of rows, please see image below:
Is there any way to match the height of the tableview according to its number of rows?
In your view controller, put code similar to the following:
override func updateViewConstraints() {
super.updateViewConstraints()
tableViewHeightConstraint.constant = tableView.contentSize.height;
}
Where tableViewHeightConstraint is an #IBOutlet to NSLayoutConstraint. Obviously with multiple table views you will need to reference multiple height constraints, so you'd just have one line in updateViewConstraints for each table view you want.
The advantage of this technique is that it takes all of the table view's content into account. It handles grouping, automatic cell height, etc.
You have to determine how many cells you have, then override
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return CGRectGetHeight(self.tableView.bounds) / self.tableView.numberOfRowsInSection(indexPath.section)
}
Btw, I suppose making use of header cells would be a better idea than implementing multiple tableviews.