TechChain
TechChain

Reputation: 8944

How to increase the height of parent view according to height of UITableView in swift?

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 ?

enter image description here

Upvotes: 7

Views: 3490

Answers (5)

LowKostKustomz
LowKostKustomz

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

Karim
Karim

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

Vitalii Gozhenko
Vitalii Gozhenko

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

iOS Developer
iOS Developer

Reputation: 558

Please go through following steps:

  1. Set row height as automatic for UITableView :

    self.tblView.rowHeight = UITableViewAutomaticDimension

  2. 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

  3. 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

iOS_MIB
iOS_MIB

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

Related Questions