Self sizing cells for nested table and collection Views - ios

I'm trying to build a table view, one of the cells in this TableView is a tabs widget.
so I'm creating this tab widget as a CollectionView. the cells of the collectionView have different subViews and each cell has it's own size.
what I'm trying to achieve is Self-sizing cells in the collectionView, but it is not working.
I'll provide you with the way I used so I can get your help.
//MARK: TableView
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DetailsTabs", for: indexPath) as! DetailsTabs /*this cell has 2 collectionViews. The first collectionView is the tabs and the second collectionView is the content that should be diplayed. I gave the first collectionView a fixed height, trailing leading and top. the second collectionView has trailing, leading bottom, and top to the first collectionView*/
cell.postDetail = postDetail
cell.widgets = self.Template
cell.parentController = self
cell.Shownavigationbar = self.Shownavigationbar
return cell
}
//MARK: DetailsTabs Class
override func awakeFromNib() {
//code to setUp the collectionViews
//pagesLayout is the UICollectionViewFlowLayout for the second collectionView
pagesLayout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 1)
}
//MARK: IN collectionView Cells I added this function:
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height)
layoutAttributes.frame = frame
return layoutAttributes
}
note: the content of the collectionView cells might be webView or tableview.

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
you should use UITableViewAutomaticDimension in estimatedHeightForRowAtIndexPath
hope this is working fine for you...!

Related

Tableviewcell height with inside tableView

I have a tableView in which every cell contains another tableView with dynamic row height.
My question is how can I set the row height of the first table to fit the height of the inner tableView?
I'm using this code but it does not work as it should.
var heights: [CGFloat] = []
var loades: [Bool] = []
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.heights[indexPath.row]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as! EventCell
cell.date.text = ev.date
cell.delegate = self
cell.event = ev
self.heights[indexPath.row] = cell.tv.frame.height
if self.loades[indexPath.row] == false{
self.loades[indexPath.row] = true
tableView.reloadRows(at: [indexPath], with: .none)
}
return cell}
I'd try getting the nested tableview's contentSize in your heightForRow method.
I hope you can access to your tableview.contentSize.height, the contentSize gets the value of all tableview content if your tableview is dynamic, the content of this height you can divide in the number of rows what you have. This is just a simply solution, some like this:
let size = tableView.contentSize.height
let cellSize = size / models.count
where models is the array of objects printed in tableviewcell inside tableview
Recommend:
Put a height constraint inside your cell to your tableView, and try to refresh with de sizeCell sum
cell.tableViewInsideCell.reloadData()
cell.heightConstraint.constant = tableView.contentSize.height
and set
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}

Default UITableViewCell height is to big for the text

I have an UITableView with a default cell where I just add a string:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
cell.textLabel?.text = tasks[indexPath.row].name
cell.textLabel?.textColor = .white
cell.textLabel?.textAlignment = .center
return cell
}
My problem is that the cell is too big for just some normal text. Here is a screenshot, the cell has the blue background:
I didn't have this issue before, when my data source was an array on String's. The issue appeared after I changed from Strings to custom objects. Not sure if this is related.
How can I fix this ? I tried setting the row height to custom value, but it doesn't have any effect.
edit with table view code:
extension TasksViewController {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
cell.textLabel?.text = tasks[indexPath.row].name
cell.textLabel?.textColor = .white
cell.textLabel?.textAlignment = .center
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dummyTxt.textField.text = tasks[indexPath.row].name
dummyTxt.becomeFirstResponder()
dummyTxt.textField.becomeFirstResponder()
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let delete = UITableViewRowAction(style: .destructive, title: "Delete") { (_, index) in
self.tasks.remove(at: index.row)
}
return [delete]
}
}
Set this on tableView:
tableView.estimatedRowHeight = 44
tableView.rowHeight = UITableViewAutomaticDimension
Do NOT override heightForRowAt delegate method.
And then just make sure that the prototype cell that you registered as "Cell" has proper constraints that can be used to calculate its height. In your case make sure that both top and bottom anchors of the label are constrained to the top and bottom anchors of the cell.
Use following delegate method with returning some integer value, if you need same size for every cell.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
Hopes It may help you.
Try this:
To set automatic dimension for row height & estimated row height, ensure following steps to make, auto dimension effective for cell/row height layout.
Assign and implement tableview dataSource and delegate
Assign UITableViewAutomaticDimension to rowHeight & estimatedRowHeight
Implement delegate/dataSource methods (i.e. heightForRowAt and return a value UITableViewAutomaticDimension to it)
-
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Don't forget to set dataSource and delegate for table
table.dataSource = self
table.delegate = self
// Set automatic dimensions for row height
table.rowHeight = UITableViewAutomaticDimension
table.estimatedRowHeight = UITableViewAutomaticDimension
}
// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
For label instance in UITableviewCell
Set number of lines = 0 (& line break mode = truncate tail)

How to set heightForRowAt based the number of numberOfItemsInSection?

I'm using UITableViewController and put UICollectionView in second row in Table View Cell. The problem is how I can get heightForRowAt dynamically.
I have tried using return UITableViewAutomaticDimension. But not working.
Any help is really appreciated.
viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.estimatedRowHeight = self.tableView.rowHeight
self.tableView.rowHeight = UITableViewAutomaticDimension
}
UITableViewController
Option 1
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return self.tableView.bounds.width + 15
}
Option 2
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Currently, I hard code the number of returns.
UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
UICollectionViewDelegate, UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let layout = collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumLineSpacing = 2.5
layout.minimumInteritemSpacing = 2.5
itemWidth = (collectionView.bounds.width - 5.0) / 3.0
return CGSize(width: itemWidth, height: itemWidth)
}
Here is the image of UI using return self.tableView.bounds.width + 15 :
Here is the image of UI using return UITableViewAutomaticDimension :
Here is the image of Constraints :
In your viewDidLoad() try adding this -:
override func viewDidLoad() {
super.viewDidLoad()
yourTableView.estimatedRowHeight = 70 // this is your storyboard default cell height
yourtableView.rowHeight = UITableViewAutomaticDimension //Automatic dimensions
}
Then try this -:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
In your case, you have to give dynamic height for your cell which has a collection view depending on the content height of your collection view, but while loading your table view that time may be your collection view would not be loaded completely thus that time your collection view's content height might not be right.
In order to get the right content height you have to calculate collection view's content height like below:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//Your cell which has a collectionview
if indexPath.row == 1{
let contentHeight = (numberOfCollectionViewcell*itemHeight)+collectionViewContentOffset
return contentHeight
}
return self.tableView.bounds.width + 15
}
From CollectionViewDelegate yon can identify when collectionview is fully loaded
get the CollectionView content height.
Send this content height to the tableView VC by creating delegate.
In delegate method reload tableView.
In tableViewCell CollectionView is already reloading so every time when you do above method compiler goes to infinity for reloading tableView and collectionView. For this you need to add a flag (isForcefullyReloadCollectionView), flag is true when tableview is tableview is need to reload otherwise false. You need to add this flag where you going to forcely reload the tableView.
Do this above, If you need further help you can ask. If I got any other solution then I update you.

Self sizing cell not working until scrolling some items

I'm using self sizing UITableViewCell with some labels inside and all labels lines number is 0.
tableView.estimatedRowHeight = 284
tableView.rowHeight = UITableViewAutomaticDimension
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SearchCell", for: indexPath) as! NodeCell
let nodemodel = nodes[indexPath.row]
cell.like.text = Utils.convert_string(string: String(nodemodel.like))
cell.address.text = nodemodel.address
cell.avatar.downloadedFrom(link: "www.example.com")
cell.avatar.layer.cornerRadius = cell.avatar.frame.size.width / 2
cell.avatar.layer.borderWidth = CGFloat(integerLiteral: 1)
cell.avatar.layer.borderColor = UIColor.black.cgColor
cell.avatar.clipsToBounds = true
cell.title.text = nodemodel.node_name
cell.layoutIfNeeded()
return cell
}
after running application all of my labels limited to single line and texts not showing completely until scrolling some items and then scrolling back. what is wrong? I did layoutIfNeeded() before returning cell but it's not working
problem is solved after changing UIStackView distribution mode from Fill Proportionally to Equal Spacing
Try using UITableView delegate methods instead:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat
{
return 284
}

Dynamically adjust the height of the tableview cell based on content - iOS Swift

I am trying to set the row height dynamically based on the content set in the detail text label, by using the below code in Part A.
I am inserting few lines of text into a cell's detail text label as shown below in Part B
I've looked at other similar questions but none have helped.
Can some one please advice how I can adjust the row height dynamically based on the content of the detail text label.
Part A
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Also tried
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Part B
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "daysIdentifier", for: indexPath)
cell.textLabel?.text = days[indexPath.row]
cell.detailTextLabel?.numberOfLines = 0
var joinedString = self.availabilityTimeDict[dayName]?.joined(separator: " \n ")
cell.detailTextLabel?.text = joinedString
return cell
}
Use custom cell and labels.
Set up the constrains for the UILabel. (top, left, bottom, right)
Set lines of the UILabel to 0
Add the following code in the viewDidLoad method of the ViewController:
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableView.automaticDimension
// Delegate & data source
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableView.automaticDimension;
}
Swift 4:
// Delegate & data source
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Swift 4.2:
// Delegate & data source
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
give top,bottom,leading and trailing to your lable inside content of tableview.Use below methods of table view
func tableView(_ tableView: UITableView,heightForRowAt indexPath:IndexPath) -> CGFloat
{
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat
{
return 100
}
First setup a custom cell and add a label and set its number of lines to zero and give bottom, top, leading, trailing constraints to cell's content view(dont give the height) also give a custom height to cell in size inspector then in viewDidLoad you just need to do,
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 100.0

Resources