How to set heightForRowAt based the number of numberOfItemsInSection? - ios

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.

Related

Self sizing cells for nested table and collection Views

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

How to change the cell height after putting a collection view into a table view

I'm trying to put some images with horizontal scrolling in a tableview cell, so I use a collectionview, I put it into the cell, and everything works except the cell height. I've chosen the cell height to custom in storyboard, and changed the cell height with code too, but it still doesn't work. I'm a rookie, I can't find where the problem is, please help me, thank you guys!
1.I want to change the cell height
2.Stroyboard
class HomePageTableViewController: UITableViewController {
var ImageArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
ImageArray = ["Calendar.png","Calendar.png","Calendar.png","Calendar.png","Calendar.png"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ImageArray.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BannerCell") as! BannerTableViewCell
return cell
}
override func viewWillAppear(_ animated: Bool) {
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
}
}
extension HomePageTableViewController: UICollectionViewDelegate,
UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ImageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
-> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerCollection", for: indexPath) as! BannerCollectionCollectionViewCell
cell.BannerImage.image = UIImage(named: ImageArray[indexPath.row])
return cell
}
}
You probably need to set the collectionviewcell size such as the following:
extension HomePageTableViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// Return the cell size
let cellSize = CGSize(width: collectionView.bounds.width, height: collectionView.bounds.width * (ratioToUse))
return cellSize
}
}
I've done something similar where I'm using a collectionview to scroll horizontally but I'm using the full width for each cell and calculating the aspectratio. However, you'll need to modify this for the size you want.
I had to do some tricks elsewhere to size the collectionview itself as well.
I would try this first then, if you're still having problems, post an image of what it looks like.
Update #2:
If you are using AutoLayout, you shouldn't need to do this but you can set the height yourself using the following:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
<#code#>
}
Update #3:
I just some testing with this. You should put a height constraint on your collectionview and that should make the tableviewcell resize appropriately. You shouldn't need "heightForRowAt" as I mentioned above. AutoLayout should handle this for you.
Try to change the content mode of the UIImageView to aspect fit. It might work.

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

iOS: UITableView inside UITableViewCell with dynamic cell height

I want to implement UITableView inside UITableViewCell with dynamic height of cell according to inside UITableView content size. How can I implement this any suggestions?
I want layout something like this...
Code work:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let identifier = "OrderHistoryTVCell" let cell: OrderHistoryTVCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? OrderHistoryTVCell
let tableInnerContentSize = cell.tableInner.contentSize.height
let nn = cell.viewAfterTable.frame.height+tableInnerContentSize
return nn
}
use following:
#IBOutlet weak var tableView: UITableView! //connect the table view
//do following in viewDidLoad method
tableView.estimatedRowHeight = 100 //Your estimated height
tableView.rowHeight = UITableViewAutomaticDimension
Also set these two properties of UILable from Attributes inspector section of storyboard:
lines to 0
Line break to word wrap
or you can also set these properties from code:
self.lblxyz.numberOfLines = 0
self.lblxyz.lineBreakMode = .byWordWrapping
Note - Add constraint properly in table view cell.
You have to do something like this:
In ui Master-Item # is be your section header. So take UILabel and add it as a section header.
Your sub-item is the prtotype-cell cell which contains one label.
Constraints for label inside cell.
In your cell first add UIView with constraints as follows:
Top , Bottom , Leading, Bottom to superView as 0.
Now add label and give constraints as follow.
Top , Bottom , Leading, Bottom to UIView as 8.
Give height constraint as per your requirement.
Give height relationship from = to >=.
Set label property line to 0 from storyboard.
Implement this lines in
//MARK:- TableView
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat{
return 60 // return header height
}
public func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
// return your section header i.e. master item label
}
public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat{
return 50;
}
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return UITableViewAutomaticDimension
}
public func numberOfSections(in tableView: UITableView) -> Int{
// return number of section i.e. total count of master item.
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
// returns number of cells in each section
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
// return your custom cell here
//eg:
// cell.labelFood.text = your data
}
NOTE Don't forget to bind delegate and dataSource of tableView.
use this code in viewDidLoad()
self.tableView.estimatedRowHeight = 350
self.tableView.rowHeight = UITableViewAutomaticDimension
Use this Delegate
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
self.tableView.estimatedRowHeight = 160
return UITableViewAutomaticDimension
}
Also set these two properties of UILable.
#IBOutlet weak var label: UILabel!
label.numberOfLines = 0

How to create static cells with dynamic cell heights with Swift

I have looked at several tutorials that show how to set dynamic cell heights, but all of them only show it if you are using dynamic cells by setting the appropriate constraints and using UITableViewAutomaticDimension. However, I would like to do this for static cells.
I have a table view controller in my app that contains several cells that display a category with a disclosure indicator in which there is a title and then a description and the size of the description text varies. Thus, I would like the height of the cell to be dynamic per the size of the description text.
The reason why I am using static cells and not dynamic cells is because above the category cells I have a few cells with some designs that I could only get by using static cells and storyboarding.
I am using iOS9, Xcode 7.3 and Swift 2.2
UPDATE
Table View Controller Code
import UIKit
class CategoriesTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 2
}
}
UPDATE 2
Per accepted answer below I added the two methods below to my table view controller and removed the 2 lines I had in viewDidLoad(). This did it for me! Keep in mind that I had to make sure all the labels in each cell used a top, bottom, leading and trailing constraint. Also, the number of lines for each label must be set to 0.
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
UILabel:
Set numberOfLines = 0 via programmatically or set lines to zero in attributes inspector of the UILabel.
UITextView:
Let's select your text view and uncheck the scrolling enabled like as below image.
Add the below code to your view controller:
Swift 5:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Swift 2.2:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
For Swift 3
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
All you have to do is set proper AutoLayout inside the cell, so the height increases based on the length of the description text.
Then you need to set the following in your viewDidLoad
tableview.rowHeight = UITableViewAutomaticDimension
tableview.estimatedRowHeight = 44
Please note: you need to set the numberOfLines of UILabel to 0
#Forge, add please to your topic
Swift 4 variant:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
#Forge answer Swift 5 variant,
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}

Resources