I have cells with dynamic height inside an UITableView.
In interface builder, everything looks good.
These are my constraints:
But on the device, there is added empty space at the top and bottom of some messages. There would be no problem if the label's greater than or equal constraint would be an equality constraint, but the bubbles have the width of the screen.
This is my cell configuration:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row % 2 == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "ReceivedMessage") as! MessageTableViewCell
cell.messageLabel.text = arr[indexPath.row]
cell.setNeedsLayout()
cell.setNeedsDisplay()
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "SentMessage") as! MessageTableViewCell
cell.messageLabel.text = arr[indexPath.row]
cell.setNeedsLayout()
cell.setNeedsDisplay()
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
Any idea why this is happening? Thanks.
Related
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
}
My question is related to this one: How to change height Constraint of UIView in UitableviewCell when using UITableViewAutomaticDimension
The solution there does not seem to be working for me.
In the image above i have a simple cell.
On tap of cell, i want to change the constraint of the redView to be larger. This should then automatically change the height of the cell.
I already have the height constraint of the cell set to an #IBOutlet and i think i am correctly changing the size of the cell, but it is not working.
Here is my sample app that is not working. Any help? SampleApp - for Xcode 9.3
You need to set a bottom constraint to the red view so auto-layout can stretch the cell after setting the constant value
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "c", for: indexPath) as! customcell
configure(cell: cell, indexPath: indexPath)
cell.redview.backgroundColor = .red
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! customcell
cell.constraint.constant = data[indexPath.row] == "contracted" ? 30 : 200
data[indexPath.row] = data[indexPath.row] == "contracted" ? "expanded" : "contracted"
tableView.reloadData()
}
func configure(cell: customcell, indexPath: IndexPath) {
let data = self.data[indexPath.row]
if data == "expanded" {
cell.constraint.constant = 200
} else {
cell.constraint.constant = 30
}
cell.layoutIfNeeded()
}
}
Calling the below will recalculate the heights.
[tableView beginUpdates];
[tableView endUpdates];
I have JSON object where one key is interface_id and I want to set Cell height accordingly, When I try to set height 0, after that tableView stuck while scrolling.
public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat{
if (dataArray[indexPath.row] as AnyObject).value(forKey: "interface_id") as! Int == 1{
return 0
}else{
return UITableViewAutomaticDimension
}
}
Basically, to use self sizing cells, for the UITableView you will set an estimated row height, and also set the rowHeight to a value of UITableViewAutomaticDimension. so changing the Cell height for row your code should be look like that.
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 44.0
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (dataArray[indexPath.row] as AnyObject).value(forKey: "interface_id") as! Int == 1{
return 0
}else{
return UITableViewAutomaticDimension
}
}
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)
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
}