I have table view in which I have another table view. Actually I make dynamic section with cells coming from backend.
The problem is that is not showing the last cell.
Here is the main table view height setting:
//This code is in first view controller updating table view height
override func updateViewConstraints() {
tableViewHieght.constant = tableView.contentSize.height
super.updateViewConstraints()
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{
tableView.layer.removeAllAnimations()
tableViewHieght.constant = tableView.contentSize.height
UIView.animate(withDuration: 0.5) {
self.updateViewConstraints()
}
}
Add picture for more clarification
I don't know what I should do for second table view that is in cell so it adopt the dynamic size.
The actual output:
I work on it and i realised the problem is with first table view row height i inspect the constraint and all settings that is necessary for making it dynamic but still it not growing i did a lil hack but i really want to do it with tableview.automatic dimension
// this is first table view cell in that cells every cell contain a label and a table view a second one which contain some label that making a format like section and cells In second table view I used Table view.automatic dimension
Related
There is table view in scroll view, for the perfect scrolling need height of table view. But there is dynamic height of cell and in cell multiple content with dynamic data like image(calculating height of image with kingfisher library) and content(with 0 number of lines). So unable to calculate height of each cell. So I am using this for getting height of cell:-
let totalCount = self.itemArray.data1.count + self.itemArray.data2.count
if totalCount != self.totalHeightOfTable.count {
//Appending height of cell
self.tableView.reloadData()
self.totalHeightOfTable.append(cell.frame.height)
self.heightOfPost = self.totalHeightOfTable
if totalCount == self.totalHeightOfTable.count {
// Call back to get height of tableView
self.getTotalHeightOfTableView?(self.totalHeightOfTable)
}
}
because the tableView is inside a scrollview , I am not able to calculate the height for each cell of the tableView dynamically or at run time. The height I get at runtime is greater and there is a blank white space at the end of the tableView. So the total height for table view is always greater than the sum of all the cells in the table view.
UI structure attached
I understood your problem that you want to calculate dynamic table height with flexible cells height inside tableview and according to this height you want to update your parent scrollview contentSize height .
I want to tell you that please remove your all your height calculation and just place this below simple function in side your view controller.
IMPORTANT:- Don't give any Height Constraint to your table view if you are using AutoLayout from your storyboard or programatically.
kindly take care of your variable names of tableview and scrollview and replace them respectively .
//MARK:- viewDidLayoutSubviews will call after dynamic height calculation automatically
override func viewDidLayoutSubviews() {
//isScrollEnabled of table view should be dissable because our table is inside scrollview.
tableView.isScrollEnabled = false
//if above tableView.contentSize.height not zero and giving acurate value then proceed further and update our parent scroll view contentsize height for height.
print(tableView.contentSize.height)
//place some bottom peeding as you want
let bottomPedding:CGFloat = 30
//Finally update your scrollview content size with newly created table height + bottom pedding.
scrollview.contentSize = CGSize.init(width: scrollview.contentSize.width, height:tableView.contentSize.height + bottomPedding)
}
if this will work then fantastic then great , rest you can contact me any time we will figure it out.
asrathoreforiphone#gmail.com
You can use the height of the contentSize by taleView.contentSize.height
Welcome to Stackoverflow!
You can definitely get the contentSize, and get the height from that, of your tableView. I've been using this method and works every time.
One way to do it is to add an observer, like so:
tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
and then override your controller's method, observeValue, like so:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let obj = object as? UITableView {
if obj == self.tableView && keyPath == "contentSize" {
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
let height = newSize.height // <----- your height!
}
}
}
}
To add, perhaps it would be best if in your viewWillDisappear or deinit method, remove that observer.
I have a UICollectionViewCell which has a UTableView inside it. I want to calculate the height of UITableView dynamically based on the content inside it. It means, the UITableView shouldn't scroll but should increase/decrease its height according to its content.
You can use a self sizing table view like this:
class SelfSizingTableView: UITableView {
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
}
In addition you have to make sure to set up constraints in your collection view cell correctly (a full set of constraints from the top of the collection view cell to the bottom of it).
I've been there. There are multiple ways to do that, especially if your rows really have constant height, that should be easy. Multiply the number of rows to the constant height, voila, you have your tableView height.
HOWEVER, if you have dynamic cell height of the tableView that is inside the collectionViewCell or tableViewCell (they're the same), then you need another approach.
My approach to that is observing the keyPath contentSize. This one is perfect, I've been using this in my main production project. Here's a full block of the code that I use, including the comments/documentation ;)
/**
Important Notes, as of 12/18/2018, 9:41PM, a eureka moment:
- No need for label height.
- Needs a reference for tableViewHeight.
- After observing the newSize data, update the constraint's offset of the tableViewHeight reference.
- And then let know the controller to not reload the data of the tableView but rather begin and end updates only.
- beginUpdate() and endUpdate() lets the tableView to update the layout without calling the cellForRow, meaning without calling the setupCell method.
*/
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let obj = object as? LLFTableView, obj.tag == 444 {
if obj == self.tableView && keyPath == "contentSize" {
if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
// Edit heightOfTableViewConstraint's constant to update height of table view
llfPrint("New Size of the tableView: \(newSize) ✅✅✅✅✅")
DispatchQueue.main.async {
self.constraint_TableViewHeight?.update(offset: newSize.height)
self.delegate?.reloadData()
}
}
}
}
}
So, what happens in the controller or viewModel that implements such reloadData delegate method? It calls another delegate method to just let know the controller (That holds the super tableView) that we're updating the height of the cell.
self.tableView.beginUpdates()
self.tableView.endUpdates()
That's it! :) I hope this helps!
I'm trying to hide table view and remove space. But the table view space not removed. When first time user coming this page there is no data inside the table view so I write ishidden=true.table hidden but space not remove.user add data manually and table view appear.this working proper after add data .
I'm trying
self.tableView.tableFooterView = UIView()
self.tableView.ishidden=true
above code table hidden but not remove table space. So how to remove space of hide table view..
You need to set the height constraint for table view.
The best place to set the height is numberOfSectionsInTableView function.
This function called once on every reload of data.
//Assuming your data source
var dataSource: [String] = []
//connect this outlet to tableViewHeight Constraint
#IBOutlet var tableViewHeight: NSLayoutConstraint!
//connect this outlet to tableView
#IBOutlet var tableView: UITableView!
func numberOfSections(in tableView: UITableView) -> Int {
//need to check the data availability
if self.dataSource.count == 0{
//need to set the table height constraint to zero
self.tableViewHeight.constant = 0
self.tableView.isHidden = true
return 0
}
else {
//need to set the table height constraint to desired frame.
self.tableViewHeight.constant = self.view.frame.size.height //Assuming full screen.
self.tableView.isHidden = false
return 1
}
If you just want to hide tableView then just set the tableView.alpha to 0 and disable tableView interaction. You can set your no data view before tableview in storyboard hierarchy and then manage with tableview alpha values to hide and show no data view
you can do with the help of tableview contentSize observer key.For that you have to take Outlet of tableview height and set into tableView observer method.
Set tableView scroll disable.
override func viewWillAppear(_ animated: Bool) {
tbl.addObserver(self, forKeyPath: "contentSize", options: [.new], context: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
tbl.removeObserver(self, forKeyPath: "contentSize")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if object is UITableView {
print("contentSize:= \(tbl.contentSize.height)")
self.heightTbl.constant = tbl.contentSize.height
}
}
Hope this will help you.
I want to create a cell that consist of title text, description text, and a collection view. So I tried to created a cell like this
I added top, trailing, and leading to superview constraint for title and description. Then I also add top, bottom, trailing, and leading constraint to my UICollectionView.
For auto height my tableview cell, I override viewWillAppear
override func viewWillAppear(_ animated: Bool) {
tableView.estimatedRowHeight = 300
tableView.rowHeight = UITableViewAutomaticDimension
}
And in my custom cell class, I called layoutIfNeeded()
public func setRowWithData(model: DataModel) {
// set your view here
contentView.layoutIfNeeded()
}
What I want is, all of cell in collectionView is showed and my tableViewCell's height will adapt into it.
Is there any way to do it? Any help would be appreciated. Thank you!
You can user content size observer of collection view to change the height of collection view according to its content at runtime.
To add the observer to your collection view you can use below method.
self.collectionView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.old.union(NSKeyValueObservingOptions.new), context: nil)
By using below callback method you can set the collection view height runtime.
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
self.collectionViewHeight.constant = self.collectionView.contentSize.height
}
I have a UIStackView where it can show a label, image, table view or nothing based on user selection. Here is my current hierarchy for the dynamic view:
UIStackView_Parent
UILabel - some text, fixed view
UIStackView_Child - this is the container that can show multiple things or nothing
UIView - another fixed view
When I call UIStackView_Child.addArrangedSubview(...) with a label or image it works perfectly, but addArrangedSubview(tableView) does not show the table. I have tableView.scrollEnabled = false and set frame to fixed height based on number of cell and defined the table's cellHeight.
Any help would be much appreciated, thanks!
Another way to do this without explicitly setting the frame height and width is to embed your table view inside an empty view, pin the table view to the top, bottom, left and right and set a "greater than or equal to" constraint to the table view's height.
That's because stackview tries to compress content as much as possible. When you initally add a tableview, I'm assuming it has no content, so stackview compresses the width to 0 because it has nothing to show. You have to do one of two things:
After the table gets populated with data, you have to set the tableView's frame. I do this by calculating how big each cell is going to be. I know the width is going to be as big as the view that contains stackview. So it winds up being something like
let estimatedHeight = tableView.numberOfRows(inSection: 0) //You may need to modify as necessary
let width = parentView.frame.size.width
tableView.frame = CGRect(x: 0, y: 0, width: width, height: estimatedHeight)
Once you set the tableView's frame, stackview should automatically adjust.
You can also automatically monitor the height of the UITableView with Combine:
import Combine
var tableViewHeightConstraint: NSLayoutConstraint?
var cancellables: Set<AnyCancellable> = []
// Table View Content Size monitor
tableView.publisher(for: \.contentSize)
.receive(on: DispatchQueue.main)
.sink { self.tableViewHeightConstraint?.constant = $0.height }
.store(in: &cancellables)
Or if you don't have combine available you can add an Observer:
tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if(keyPath == "contentSize") {
// Here you could get from change or simple get it directly from the table view
tableViewHeightConstraint?.constant = tableView.contentSize.height
}
}