I am developing a UITableViewCell that starts as a xib, has views added to it programmatically, and has a dynamically sized height. However, it looks like when adding the programatic views with constraints, it is conflicting with the auto-resize constraint initially applied to the xib, and causing issues. Please see below:
Dequeuing my cells:
//Table Delegate/Datasource
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:S360SSessionMatchTableCell? = tableView.dequeueReusableCellWithIdentifier(XIBFiles.SESSIONMATCHTABLECELL + String(indexPath.row)) as? S360SSessionMatchTableCell
if ((cell == nil)){
tableView.registerNib(UINib(nibName: XIBFiles.SESSIONMATCHTABLECELL, bundle: nil), forCellReuseIdentifier: XIBFiles.SESSIONMATCHTABLECELL + String(indexPath.row))
cell = tableView.dequeueReusableCellWithIdentifier(XIBFiles.SESSIONMATCHTABLECELL + String(indexPath.row)) as? S360SSessionMatchTableCell
}
cell!.setupEvents(sessionMatches[indexPath.row]["sessions"]! as! [[String:String]])
return cell!
}
Setup Events Method in Custom UITableViewCell:
func setupEvents(events:[[String:String]]){
//Set up start and end times
self.startTimeLbl.text = events[0]["startTime"]!
self.endTimeLbl.text = events[events.count - 1]["endTime"]!
//Set up events
var pastEventView:S360SScheduledEventView? = nil
var pastEvent:[String:String]? = nil
for (index, event) in events.enumerate(){
var topAnchor:NSLayoutConstraint!
//Create event view
let eventView:S360SScheduledEventView = NSBundle.mainBundle().loadNibNamed(XIBFiles.SCHEDULEDEVENTVIEW, owner: self, options: nil)[0] as! S360SScheduledEventView
//Deal with first view added
if pastEvent == nil{
//Top anchor setup for first view
topAnchor = NSLayoutConstraint(item: eventView, attribute: .Top, relatedBy: .Equal, toItem: toLbl, attribute: .Bottom, multiplier: 1, constant: 10)
}
else{
//Check for a break
let timeFormatter:NSDateFormatter = NSDateFormatter()
timeFormatter.dateFormat = "hh:mm a"
let startTime = timeFormatter.dateFromString(pastEvent!["endTime"]!)
let endTime = timeFormatter.dateFromString(event["startTime"]!)
if startTime != endTime {
//Create break view
let breakView = NSBundle.mainBundle().loadNibNamed(XIBFiles.SCHEDULEDBREAKVIEW, owner: self, options: nil)[0] as! S360SScheduledBreakView
//Setup breakview constraints
let bTopAnchor = NSLayoutConstraint(item: breakView, attribute: .Top, relatedBy: .Equal, toItem: pastEventView, attribute: .Bottom, multiplier: 1, constant: 0)
let bLeftAnchor = NSLayoutConstraint(item: breakView, attribute: .Leading, relatedBy: .Equal, toItem: self.contentView, attribute: .LeadingMargin, multiplier: 1, constant: 0)
let bRightAnchor = NSLayoutConstraint(item: breakView, attribute: .Trailing, relatedBy: .Equal, toItem: self.contentView, attribute: .TrailingMargin, multiplier: 1, constant: 0)
let bHeightAnchor = NSLayoutConstraint(item: breakView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 30)
//Add break view and constraints
self.addSubview(breakView)
self.addConstraints([bTopAnchor, bLeftAnchor, bRightAnchor, bHeightAnchor])
//Top anchor setup for subsequent view
topAnchor = NSLayoutConstraint(item: eventView, attribute: .Top, relatedBy: .Equal, toItem: breakView, attribute: .Bottom, multiplier: 1, constant: 0)
}
else{
//Top anchor setup for subsequent views
topAnchor = NSLayoutConstraint(item: eventView, attribute: .Top, relatedBy: .Equal, toItem: pastEventView, attribute: .Bottom, multiplier: 1, constant: 0)
}
}
//Setup other anchors
let leftAnchor = NSLayoutConstraint(item: eventView, attribute: .Leading, relatedBy: .Equal, toItem: self.contentView, attribute: .LeadingMargin, multiplier: 1, constant: 0)
let rightAnchor = NSLayoutConstraint(item: eventView, attribute: .Trailing, relatedBy: .Equal, toItem: self.contentView, attribute: .TrailingMargin, multiplier: 1, constant: 0)
let heightAnchor = NSLayoutConstraint(item: eventView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 60)
//Setup event view
eventView.iconImg.image = Images.get_event_image(event["title"]!)
eventView.titleLbl.text = event["title"]!
eventView.courtLbl.text = "court" + event["court"]!
eventView.timeLbl.text = event["startTime"]! + " to " + event["endTime"]!
//Add event view and constraints
self.addSubview(eventView)
self.addConstraints([topAnchor, leftAnchor, rightAnchor, heightAnchor])
//Prepare for next iteration
pastEventView = eventView
pastEvent = event
//Set up last cell with bottom bound
if index == events.count - 1 {
let bottomAnchor = NSLayoutConstraint(item: eventView, attribute: .Bottom, relatedBy: .Equal, toItem: self.contentView, attribute: .BottomMargin, multiplier: 1, constant: 0)
self.addConstraint(bottomAnchor)
}
}
}
This is the error I get (pasted once, but it occurs for each cell):
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2016-07-05 15:13:01.654 Shoot360 Scheduler[32779:642808] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x7fedd85d5590 h=--& v=--& V:[UITableViewCellContentView:0x7fedda431120(44)]>",
"<NSLayoutConstraint:0x7fedda43a7e0 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda438b20(60)]>",
"<NSLayoutConstraint:0x7fedda436590 UITableViewCellContentView:0x7fedda431120.topMargin == UILabel:0x7fedda4312a0'10:00 AM'.top - 15>",
"<NSLayoutConstraint:0x7fedda436630 UILabel:0x7fedda431c00'to'.top == UILabel:0x7fedda4312a0'10:00 AM'.top>",
"<NSLayoutConstraint:0x7fedda433b60 V:[UILabel:0x7fedda431c00'to']-(10)-[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda438b20]>",
"<NSLayoutConstraint:0x7fedda445910 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda4443f0(60)]>",
"<NSLayoutConstraint:0x7fedda448310 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda438b20]-(0)-[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda4443f0]>",
"<NSLayoutConstraint:0x7fedda449a00 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda448540(60)]>",
"<NSLayoutConstraint:0x7fedda4479e0 V:[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda4443f0]-(0)-[Shoot360_Scheduler.S360SScheduledEventView:0x7fedda448540]>",
"<NSLayoutConstraint:0x7fedda44a100 Shoot360_Scheduler.S360SScheduledEventView:0x7fedda448540.bottom == UITableViewCellContentView:0x7fedda431120.bottomMargin>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7fedda436590 UITableViewCellContentView:0x7fedda431120.topMargin == UILabel:0x7fedda4312a0'10:00 AM'.top - 15>
Row height is being set to dynamic:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//Styling
showAllBtn.layer.cornerRadius = Numbers.CORNERRADIUS
sessionsTbl.rowHeight = UITableViewAutomaticDimension
sessionsTbl.estimatedRowHeight = 500
sessionsTbl.layer.borderColor = Colors.REALLIGHTGREY.CGColor
sessionsTbl.layer.borderWidth = Numbers.BORDERREG
sessionsTbl.layer.cornerRadius = Numbers.CORNERRADIUS
sessionsTbl.separatorStyle = UITableViewCellSeparatorStyle.None
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}