Reputation: 8944
I have below hierarchy of my screen.
-ScrollView
-ContentView
-View1
-View2
-View3
-Collectioview
-CollectioviewCell
-Tableview
-Tableviewcell
-Content
Now here my content of tableview is dynamic so height of tableview cell can't be static.So height of tableview will increase according to number of cell & height of each cell.
Based on Tableview height, Height of collection view should increase which results in increase in height of scroll view content view.
But I am not able to understand how should achieve this with less code? or can it be done programatically ?
Upvotes: 7
Views: 3490
Reputation: 424
The most universal way is to observe contentSize
property of your scroll-/table-/collectionView and to change size accordingly.
To achieve this you should:
Note: examples will be for UIScrollView, but it can be applied for any collectionView
add observer to your view
scrollViewToObserveSizeOf.addObserver(observerObject, forKeyPath: "contentSize", options: [.old, .new], context: nil)
override observeValue
method
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let scrollView = object as? UIScrollView,
scrollView == scrollViewToObserveSizeOf,
keyPath == "contentSize" {
// Do whatever you want with size
// You can get new size from scrollView.contentSize
// or change?[NSKeyValueChangeKey.newKey] as? CGSize for new value
// and change?[NSKeyValueChangeKey.oldKey] as? CGSize for old value
//
// ! Do not force unwrap this values, just never use force unwrap,
// everything could happen
} else {
// ! Do not forget to call super.observeValue(forKeyPath:of:change:context)
// if it is not object you added observer to
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
To apply it, for example, to UITableView just check if object in observeValue
method is of UITableView
type.
This method is called whenever content size of your collection view is changed and you do not need to know anything about if your view has finished loading or whatever.
Upvotes: 4
Reputation: 402
change you hierarchy,this is not a good idea, but it works
-CollectionView
-CollectioviewCell
-CollectioviewCell
-CollectioviewCell
-CollectioviewCell
-Collectioview
-CollectioviewCell
-Tableview
-Tableviewcell
-Content
Upvotes: 0
Reputation: 9354
You can override UITableView
property intrinsicContentSize
and return contentSize
there. Then when you have some changes in table view content size, just call invalidateIntrinsicContentSize()
to relayout
YourCustomTableView:
override var intrinsicContentSize: CGSize { return contentSize }
YourViewController or code where you handle layout:
func refreshViewController() {
// do some stuff with your custom table view
yourCustomTableView.invalidateIntrinsicContentSize()
}
Upvotes: 0
Reputation: 558
Please go through following steps:
Set row height as automatic for UITableView :
self.tblView.rowHeight = UITableViewAutomaticDimension
Similarly for collection view, if you haven't managed the size of the cell you can refer: https://medium.com/@wasinwiwongsak/uicollectionview-with-autosizing-cell-using-autolayout-in-ios-9-10-84ab5cdf35a2
Now create height constraint for ContentView and set its value as:
contentViewHieghtConstraint.constant = collectionView.contentSize.height
This will solve your problem.
But your current controls setup seems very clumsy, I suggest you should go with any other approach to set up fewer controls in single view controller if possible.
Upvotes: 1
Reputation: 1895
Let's suppose each row in your table view has fixed height.
So height of table view would be number of row in tableview * height of row. Suppose hight of each row is 30 and there are 4 rows in table view then,
tableHeight = 4*30 = 120
You don't have to wait for tableview to reload data. You can use the count of your array from which you fill your data in tableview to get number of rows. So your number of rows would be your array's count. Till here you got the height of your tableview. Now to increase the parent height, Give fixed height to the tableview and collectionview and take a outlet of height constraint of both.
Just calculate the height of tableview before reloading and give that height to tableView's height constraint. Also give the same height plus heigh of extra space(If any) to collectionView's height constraint.
For eg :
tableViewHieghtConstraint.constant = tableHeight
collectionViewHieghtConstraint.constant = tableHeight
This will increase your collectionview's and tableView's height and thus result in increasing the height of your content view.
If you want to calculate the height of your tableview with dynamic height of each cell, following method can be used to get height. Though this is not recommended and does not work in every case so use this with your own consent.
func reloadData() {
self.tableView.reloadData()
let tableHeight: CGFloat = 0
DispatchQueue.main.asyncAfter(deadline: .now()+0.3) {
for i in 0...aryData.count - 1 {
let frame = self.tableView.rectForRow(at: IndexPath(row: i, section: 0))
tableHeight += frame.size.height
print(frame.size.height)
}
}
tableViewHieghtConstraint.constant = tableHeight
collectionViewHieghtConstraint.constant = tableHeight
}
You can avoid using delay or provide less delay. Delay is given here in case if there is large amount of data to be processed and displayed on table view then it might take some fraction of seconds.
P.S: Don't forget to give bottom constraint of collectionview to contentview.
Upvotes: 1