hello I have a dynamic TableViewController in which there is one cell which has one image, and labels. I have set constraint of all of them. The problem is its not viewing correctly.
This is how its viewing
Code:
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 103
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.setNeedsLayout()
tableView.layoutIfNeeded()
self.tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return newarray.count
}
override
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("requestcell", forIndexPath: indexPath) as! NewRequestTableViewCell
let image : UIImage = UIImage(named: "placeholder_product_image")!
cell.imageView!.image = image
cell.requestTitle.text = "IPHONE 6s PLUS"
cell.DestinationCountry.text = "Pakistan"
return cell
}
I don't know what else to do. Please help how can I have row like I designed
The problem here is the height of your cell
add the following methods in your code: (replacing of course <#cell_height#> by the value of your choice, or by UITableViewAutomaticDimension)
override func tableView(_ tableView: UITableView,
heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return <#cell_height#>;
}
In order for tableView self sizing to work, you need to add constraint to both top and bottom of UILabel.
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 103
I think your trying is right, but you need to increase the estimatedRowHeight. i.e, 300 or 600.
And you need to add constraints on Storyboard suitably.
so just add up, left, right, bottom distance constraints.
Never give the width & height constraints there.
Beside you need to call the cell.contentView.layoutIfNeeded just in the cellForRowAtIndexPath method.
I think it will work then.
Sincerely,
Harri.
Related
I created UITableViewController to show reviews, shown in below picture.
It shows the layout correctly for the first build like below.
Correct Layout
But when I close the app and re-open it, It shows the layout like below.
Wrong Layout
I am using Xcode 12.0 and I tried on iOS 12,iOS 13 and iOS 14 same problem occurs.
Here is my code for the app: (It's a Table View Controller)
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addTapped(_ sender: Any) {
self.present(AlertService().ReviewAlert(), animated: true, completion: nil)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView.layoutIfNeeded()
}
override func numberOfSections(in 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 5
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ReviewCell", for: indexPath) as! reviewCell
// Configure the cell...
cell.ratingSetup(rating: (indexPath.row + 1))
cell.reviewLabel.text = String(repeating: "Lorem Ipsum ", count: ((indexPath.row + 1) * 5))
if indexPath.row == 1 || indexPath.row == 3 { cell.markedAsRead.isHidden = true }
cell.sizeToFit()
cell.reviewLabel.numberOfLines = 0
cell.layoutIfNeeded()
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(100)
} }
Here is my Table View Cell Content as well.
Remove methods:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView.layoutIfNeeded()
}
...
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(100)
} }
Remove:
cell.sizeToFit()
cell.reviewLabel.numberOfLines = 0
cell.layoutIfNeeded()
Set numberOfLines right in the storyboard for the label.
Check cell size field in the storyboard to be empty.
Check if you have all constraints - try to make the cell longer in the storyboard and check how label is rendered there (add long text to check if new lines are added).
Check if when launched you have no constraint warnings, if you have, then find "label to bottom" constraint and set priority from 1000 to 999.
I don't know why it happened but found a solution.
I added all other view to a Header.xib file and used basic cell type for review text.
Then It worked. Probably Cell can't handle auto dimension when there is bunch of stuff going on the prototype cell.
I'm making a TableView with UITableViewAutomaticDimension but for some reason the "extra" blank cells after the last one are the same dimensions as the last cell with text in it. I want the blank cells to all be a smaller size unless filled with text that requires the auto sizing to enlarge it. How can I change this? Any help would be appreciated. I'm very new to this. Thanks everybody! See below for a screenshot of the TableView. I've added my code for reference.
Import UIKit
class LoLFirstTableViewController: UITableViewController {
var tasks:[Task] = taskData
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 60.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
#IBAction func cancelToLoLFirstTableViewController(_ segue:UIStoryboardSegue) {
}
#IBAction func saveAddTask(_ segue:UIStoryboardSegue) {
if let AddTaskTableViewController = segue.source as? AddTaskTableViewController {
if let task = AddTaskTableViewController.task {
tasks.append(task)
let indexPath = IndexPath(row: tasks.count-1, section: 0)
tableView.insertRows(at: [indexPath], with: .automatic)
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath)
as! TaskCell
let task = tasks[indexPath.row] as Task
cell.task = task
return cell
}
}
First, you set the default row height from storyboard. The empty row will be set to this height.
Then for the rows with texts, override this table view's delegate method:
optional func tableView(_ tableView: heightForRowAt indexPath: IndexPath) -> CGFloat
This will force the table view to return the height for the specified row. Get the text from the row by its index path. Calculate the text height and return the correct row height.
Here is the method to calculate a string's frame:
func boundingRect(with size: CGSize,
options: NSStringDrawingOptions = [],
attributes: [String : Any]? = nil,
context: NSStringDrawingContext?) -> CGRect
You can just hide the empty cells by adding this to viewDidLoad():
tableView.tableFooterView = UIView()
I have a table view with height of cells set to automatic.
Once in a few runs, a few cells in the table are displayed empty (white space). Upon debugging, I noticed that the 'cellForRowAtIndexPath' function returns these cells as usual. Also, every time this bug shows up, the console has this message:
"Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead."
Scrolling up and down a couple of times fixes the issue and cells are displayed.
I use this following functions for height:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
I have been stuck with this for a week and any help would be greatly appreciated!
Edit: Code for the cells:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var row = indexPath.row
tableView.allowsSelection = false;
let cellIdentifier = "testTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! testTableViewCell
let post: PostMdl!
if(row < posts.count) {
post = posts[row]
}
else {
return cell
}
cell.label.delegate = self
cell.label.enabledTextCheckingTypes = NSTextCheckingType.Link.rawValue
cell.label.userInteractionEnabled = true
cell.brandName.text = post.brandName
cell.timeStamp.text = post.timeStamp
cell.brandImg.sd_setImageWithURL(post.brandImgUrl, placeholderImage: UIImage(named: "placeHolder"))
if let img = post.postImg {
cell.mainImg.image = img
} else {
cell.mainImg.image = UIImage(named:"lazyLoad")
}
cell.label.text = post.postTag
cell.labelDistanceFromImg.constant = 30
cell.labelDistanceToBtm.constant = 30
cell.postTag = post.postTag
cell.socNtwkImg.image = UIImage(named: post.socNtwk)
return cell
}
I guess you had set wrong constraints to subviews of UITableViewCell.contentView.
This image shows what I reproduce your error:
Please note the right constaints of red view, it just has Top Left Right Height, lacks bottom constraint, when I add it and it looks good:
Yes, there still have problem that Unable to simultaneously satisfy constraints, we can modify the priority of height constraint, default priority is required(1000), we change to Hight(750), it works!
I don't know your cell's detail, but the error's reason is likely, hope my answer helps you.
Append codes
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
return tableView.dequeueReusableCellWithIdentifier("cell")!;
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
}
What is your mobile phone version of the iOS?
In the previous iOS8 version I also encountered similar problems.
My method is as follows:
tableView.estimatedRowHeight = 88.0
tableView.rowHeight = UITableViewAutomaticDimension
Hope can help you
I have a header and a body inside my tableviewcells. I'm trying to get the body to wrap but I'm having issues.
This is the code I'm using in my view controller
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("mainCell") as? mainCell {
cell.mainHeader.text = (mainHeader[indexPath.row])
cell.mainBody.text = (mainBody[indexPath.row])
cell.mainBody.numberOfLines = 0
cell.mainBody.lineBreakMode = NSLineBreakMode.ByWordWrapping
return cell
} else {
return mainCell()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mainHeader.count
}
}
I searched and thought that the numberOfLines = 0 and lineBreakMode = NSLineBreakMode would work but it's obviously not.
Sorry if this is simple, thanks in advance.
#Daven
I know this probably won't help, but I don't think I have that or if I do I'm unsure of what it is. Also updated original code with everything that is in my VC but the vars
I have this for my custom cell
import UIKit
class mainCell: UITableViewCell {
#IBOutlet weak var mainHeader: UILabel!
#IBOutlet weak var mainBody: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func configureCell (text:String) {
mainHeader.text = text
mainBody.text = text
}
}
To make your cell expand as its label grows, you'll need to make sure you've done a few things. Set your tableView's estimatedRowHeight to a value, like
tableView.estimatedRowHeight = 200.0;
tableView.rowHeight = UITableViewAutomaticDimension
or via this method:
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 200.00
}
You also have the option of using this method, but it's not necessary if all your cells are going to vary in height:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You may also find this tutorial helpful (this is what I used :)). It shows what your autolayout constraints should look like. More information about self-sizing cells is also here.
Assuming you want your cell to expand when the text is longer than one line, you want to set the cell height to be automatic using the delegate function:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
and set the estimated row height using
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return currentInfoSelectorOption.rowHeight + 100
}
Then use autolayout in your cell to set the height. You can do this by setting the top and bottom distance constraints of the cell to the label as a constant value and setting the labels number of lines to 0. This should allow the label to expand and push the cell with it
I have an imageView on a UITableViewCell, and I want to set height of the cell / imageView to a different value compare what I set in prototype cell. I do not want to implement heightForRowAtIndexPath method, because I do not want to precalculate the height of the content. If UITableViewAutomaticDimension is set and at least on iOS 8 heightForRowAtIndexPath does not need to implement.
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 3
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell")!
let iv = cell.viewWithTag(1) as! UIImageView
iv.image = UIImage(named: "img1")
let cs = iv.constraints.first! as NSLayoutConstraint
cs.constant = 100
cell.layoutIfNeeded()
cell.setNeedsUpdateConstraints()
return cell
}
Structure of the prototype:
Although the height of the cell in prototype is set to 44.0 px, but in cellForRowAtIndexPath method I want to override this value with 100.0 px.
It'll not work the way you do.
You should implement delegate method of UITableViewDelegate
func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// calculate size of image and return its height here
}