Reputation: 139
I'm trying to create a UITableView programmatically (i.e. NO Storyboards/Interface Builder). I have a list of Notices (a simple model that has such data as a title, author, and some content). I would like the rows to be dynamically sized vertically (I am only releasing for iOS >= 8.0 so UITableViewAutomaticDimension is the height for my rows). For right now, the rows should be very straightforward. There are three UILabels. Each of which displays one of the Title, Author, and Content, in that order, with each laying out above the other; however, I am continually receiving the warning: "Detected a case where constraints ambiguously suggest a height of zero". What I understand this to mean is that my LayoutConstraints are not setup correctly; however, I have tried every combination of constraints I can think of and nothing seems to fix this warning!
Here is the cell definition:
import UIKit
public class NoticeCellView : UITableViewCell {
public static let NOTICE_CELL_REUSE_IDENTIFIER = "noticeCell"
private let titleLabel = UILabel()
private let authorLabel = UILabel()
private let contentLabel = UILabel()
public func setNotice(notice: Notice) {
titleLabel.text = notice.getTitle()
authorLabel.text = notice.getAuthorFullName()
contentLabel.text = notice.getContent()
}
public override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(titleLabel)
authorLabel.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(authorLabel)
contentLabel.translatesAutoresizingMaskIntoConstraints = false
contentLabel.numberOfLines = 0;
self.contentView.addSubview(contentLabel)
self.addConstraints([
NSLayoutConstraint(
item: self.contentView,
attribute: .Top,
relatedBy: .Equal,
toItem: titleLabel,
attribute: .Top,
multiplier: 1,
constant: 0
),
NSLayoutConstraint(
item: titleLabel,
attribute: .Bottom,
relatedBy: .Equal,
toItem: authorLabel,
attribute: .Top,
multiplier: 1,
constant: 0
),
NSLayoutConstraint(
item: authorLabel,
attribute: .Bottom,
relatedBy: .Equal,
toItem: contentLabel,
attribute: .Top,
multiplier: 1,
constant: 0
),
NSLayoutConstraint(
item: contentLabel,
attribute: .Bottom,
relatedBy: .Equal,
toItem: self.contentView,
attribute: .Bottom,
multiplier: 1,
constant: 0
),
NSLayoutConstraint(
item: self.contentView,
attribute: .Bottom,
relatedBy: .Equal,
toItem: self,
attribute: .Bottom,
multiplier: 1,
constant: 0
),
NSLayoutConstraint(
item: contentLabel,
attribute: .Width,
relatedBy: .LessThanOrEqual,
toItem: self.contentView,
attribute: .Width,
multiplier: 1,
constant: 0
),
])
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And here is the relevant snippet of the UITableViewController code:
public override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(NoticeCellView.classForCoder(), forCellReuseIdentifier: NoticeCellView.NOTICE_CELL_REUSE_IDENTIFIER)
self.tableView.estimatedRowHeight = 200
}
public override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
public override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TEST_NOTICES.count
}
public override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(NoticeCellView.NOTICE_CELL_REUSE_IDENTIFIER) as! NoticeCellView
cell.setNotice(TEST_NOTICES[indexPath.row])
return cell
}
To clarify: EVERYTHING is working (views are laid out correctly, with the constraints satisfied, etc.) EXCEPT for the height not being set dynamically. Clearing there is some constraint that I'm missing to force the contentView to expand to a non-zero height. PLEASE tell me what that constraint is before I pull my hair out.
Thanks!!
Upvotes: 1
Views: 460
Reputation: 535118
Always think about constraints like this. Every view has four features: its x-position, its y-position, its width, and its height. Look at every view and ask yourself: am I supplying enough information to determine all four of those features? If not, your constraints are insufficient.
Your constraints are grossly insufficient. You have given your attention only to height — the vertical dimension. There is no information whatever about the horizontal dimension! Where should the left edge of these labels go (the leading
edge)? You need to provide at least that much information for all three of them!
I would suggest also providing information for the right edge. The simplest way would be pin the leading edges to the leading edge of the content view, and the trailing edges to the trailing edge of the content view. (You can then delete your inequality constraint.)
Finally, you should delete the constraint with item: self.contentView
and toItem: self
. There should be no constraints to the cell itself — only to its contentView
. Similarly, delete the line that says self.contentView.translatesAutoresizingMaskIntoConstraints = false
. The content view's size/position are not up to you, and you should do nothing to mess with how they are determined.
Upvotes: 1
Reputation: 489
I have had what seems to be the same issue
Where you declare your height for the table view cell as
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You need to add an estimated height as a static number, as a fail safe.
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60 // or whatever number you choose
}
This should solve the error
Upvotes: 0