0

I have an UITableView and inside UITableViewCell, I have added view and trying to set the height of that view or height of the cell according to screen height or UITableView's height. Initially, I was able to do it but when in the viewWillAppear reloading table, not able to set the proper height for that view or height of the cell. It's the height or some other problem, not able to identify. Any help would be appreciated and Thanks for the reply. The title of the question may be confusing or do you find any unrelated code then suggestions(edits) are welcome.

Code:

import UIKit

class PageViewController: UIViewController {
    @IBOutlet weak var tblPager: UITableView!
    let screenHeight = UIScreen.main.bounds.size.height
    
    let vColors: [UIColor] = [.red, .blue, .orange, .brown, .cyan, .darkGray, .green, .red, .blue, .orange, .brown, .cyan, .darkGray, .green]

    var pageSizeHeight: CGFloat = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        pageSizeHeight = screenHeight - (getTopSafeArea() + getBottomSafeArea() + 54)
    }
   
    override func viewWillAppear(_ animated: Bool) {
        
        super.viewWillAppear(animated)
        
        delay(interval: 10.0) {
            
            print("Reload table after 10 seconds")
            self.tblPager.reloadData()
        }
    }
    
}

//MARK:- TableView Delegate
extension PageViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return vColors.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "PageCell", for: indexPath) as! PageCell
        cell.backgroundColor = vColors[indexPath.row]
        
        cell.viewHeight.constant = pageSizeHeight
        return cell
    }
    
}

class PageCell: UITableViewCell {
    @IBOutlet weak var vwPage: UIView!
    @IBOutlet weak var viewHeight: NSLayoutConstraint!
}

func getTopSafeArea() -> CGFloat {
    let window = UIApplication.shared.keyWindow
    let topPadding = window?.safeAreaInsets.top ?? 0
    return topPadding
}

func getBottomSafeArea() -> CGFloat {
    let window = UIApplication.shared.keyWindow
    let bottomPadding = window?.safeAreaInsets.bottom ?? 0
    return bottomPadding
}

func delay(interval: TimeInterval, closure: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
        closure()
    }
}

enter image description here

Output:

enter image description here

Kishan Bhatiya
  • 2,175
  • 8
  • 14
  • Show your `heightForRowAt indexPath` delegate method for the tableView. – Starsky Aug 02 '21 at 12:10
  • @Starsky I don't think so it affects the output so can you more elaborate on it? – Kishan Bhatiya Aug 02 '21 at 12:25
  • Are you trying to set the cell's height from `cellForRowAt`? – Starsky Aug 02 '21 at 12:33
  • @Starsky please check code once – Kishan Bhatiya Aug 02 '21 at 12:37
  • Since that view inside the cell is the only view, you could make it the size of the contentView, and then manipulate the cell's height inside the designated delegate method `heightForRowAt`. What you're trying to do here is not correct. If you're new to iOS development, then maybe read some answers [here](https://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights?noredirect=1&lq=1). Good luck! – Starsky Aug 02 '21 at 13:16
  • @Starsky can you try my code with your suggestion and check the final output? – Kishan Bhatiya Aug 04 '21 at 06:59
  • Do you want me to build an example project with your code and add my suggestion so that I can test it for you? If yes, then I think this is too much to ask, and you're being lazy to implement the suggestions that people give you here. – Starsky Aug 04 '21 at 09:36
  • @Starsky I already tried with the suggestion mentioned here but was not able to get output that's why asking no any other point. I'm not lazy to implement the suggestion. Sorry and have a good day. – Kishan Bhatiya Aug 04 '21 at 09:59

2 Answers2

3

Link it to tableView's height, your table view has all sizes you need.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) {
   // ...
   cell.viewHeight.constant = tableView.frame.size.heigh
   // ...
}

or remove viewHeight constraint and use delegate method to set row height

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
   return tableView.frame.size.height
}

UPD:

TableView using estimatedRowHeight to calculate its scroll offsets. This does create an issue during reload if we have enabled paging and do not configure estimatedRowHeight.

Solution 1: Implement estimatedHeightForRowAt delegate

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
     return tableView.frame.size.height
}

Solution 2: Set tableView.estimatedRowHeight = 0 and use heightForRowAt delegate instead of viewHeight constraint

Kirow
  • 1,077
  • 12
  • 25
  • thanks for the reply but your solution doesn't work. Can you please suggest another solution? – Kishan Bhatiya Aug 06 '21 at 07:39
  • this should work, I can't imagine situation when it don't. I've setup [sample project](https://github.com/Kirow/SO-68622400) for both cases – Kirow Aug 06 '21 at 11:00
  • thanks for the reply. I appreciate your effort but did you reload table view in `viewWillAppear` like `override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) delay(interval: 8.0) { print("Reload table1 after 8 seconds") self.tableView.reloadData() } }` with `delay` function which is in my code and check again your code's output? and make sure you are enable paging for tableview – Kishan Bhatiya Aug 06 '21 at 11:08
  • there is no difference. it will work, you can try it yourself – Kirow Aug 06 '21 at 11:25
  • I already tried and got the output as mentioned in the question. Make sure you are enable paging for the table view. Go to the 4th cell and wait for table reload and then check the output – Kishan Bhatiya Aug 06 '21 at 11:32
  • 1
    Ok, I see... you should set `tableView.estimatedRowHeight = pageSize`. But I suggest to use `func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath)` + `tableView.estimatedRowHeight = 0` – Kirow Aug 06 '21 at 11:36
  • thanks for your time and effort. Just update your answer then I will accept it – Kishan Bhatiya Aug 06 '21 at 11:42
  • Solution #2 helped me - Thanks! – Eduard Sep 29 '21 at 16:23
1

if all cells will have the same height, why don't you set the rowHeight property inside viewWillLayoutSubviews method?

 override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        tblPager.rowHeight = tblPager.frame.height
    }

Thanks to @Desdenova for correcting me


By setting dataSource and delegate of tblPager to self in PageViewController's viewDidLoad and setting the rowHeight property in viewDidLayoutSubviews, tableView behaves as expected.

 override func viewDidLoad() {
        super.viewDidLoad()
        tblPager.register(UINib(nibName: "PageTableViewCell", bundle: nil), forCellReuseIdentifier: "PageCell")
        tblPager.dataSource = self
        tblPager.delegate = self
    }
    
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        tblPager.rowHeight = tblPager.frame.size.height
    }

enter image description here

Amr
  • 286
  • 1
  • 2
  • 10
  • This will not work. Table doesn't know it's height when it's loaded. Try `viewWillLayoutSubviews()` – Desdenova Aug 02 '21 at 13:31
  • @Desdenova you are right but it also doesn't give required output. You can check code also – Kishan Bhatiya Aug 02 '21 at 13:33
  • It's not your fault. Question is very confusing and it has too much unrelated code. – Desdenova Aug 02 '21 at 13:36
  • thanks for the reply but your solution doesn't work. Can you please suggest another solution? – Kishan Bhatiya Aug 06 '21 at 07:39
  • sorry, that is all I could think of. can you share your code and let me try to find where the bug is? @KishanBhatiya – Amr Aug 06 '21 at 08:28
  • I've added the whole code for the controller that is containing the table view. You have to just add push action on a button on storyboard. – Kishan Bhatiya Aug 06 '21 at 09:27
  • @Amr appreciate your effort. Make sure you are enable paging for table view, go(scroll) to the 4th cell and then wait for table to reload and check output of your code. – Kishan Bhatiya Aug 06 '21 at 11:29
  • yeah, now I see what is going wrong. Is it okay to scroll to the first cell before reloading data? That -interestingly- solves the problem. @KishanBhatiya – Amr Aug 06 '21 at 12:10
  • thanks for your time and effort but I got the solution with the help of @Kirow. – Kishan Bhatiya Aug 06 '21 at 12:13